├── .gitignore ├── LICENSE ├── README.md ├── chapter01 └── asyncio │ ├── contrast_async_other.py │ ├── contrast_sync.py │ └── cotrast_async.py ├── chapter02 ├── main.py ├── static │ └── css │ │ └── style.css └── templates │ ├── index.html │ └── yyy.txt ├── chapter03 ├── async_sync │ └── main.py ├── background_tasks │ └── main.py ├── close_docs │ └── main.py ├── configparser_config │ ├── conf.ini │ └── main.py ├── debugshow │ └── main.py ├── env_config │ ├── .env │ └── main.py ├── global_exception │ └── main.py ├── localswagger │ ├── main.py │ └── static │ │ ├── swagger-ui-bundle.js │ │ └── swagger-ui.css ├── more_routers │ └── main.py ├── mount_app │ ├── fastapiapp.py │ └── flaskapp.py ├── parameter_body │ └── main.py ├── parameter_cookie │ └── main.py ├── parameter_form_and_file │ ├── data.bat │ └── main.py ├── parameter_header │ └── main.py ├── parameter_path │ └── main.py ├── parameter_query │ └── main.py ├── parameter_request │ └── main.py ├── parameter_response │ ├── data.bat │ ├── main_file_response.py │ ├── main_html_response.py │ ├── main_json_response.py │ ├── main_plain_text_response.py │ ├── main_redirect_response.py │ ├── main_response_model.py │ ├── main_status_code.py │ ├── main_streaming_response.py │ └── main_xml_response.py ├── startup_shutdown │ └── main.py ├── static_dynamic │ └── main.py └── swaggershow │ └── main.py ├── chapter04 ├── business_error │ └── main.py ├── custom_exception │ └── main.py ├── http_exception │ └── main.py ├── middleware_exception │ └── main.py └── request_validation_error │ └── main.py ├── chapter05 ├── body │ └── main.py ├── pydantic_base │ └── main.py ├── pydantic_fastapi_get │ └── main.py ├── pydantic_fastapi_post │ └── main.py ├── pydantic_field │ └── main.py ├── pydantic_obj_to_dict_json │ └── main.py ├── pydantic_orm │ └── main.py ├── pydantic_validator │ ├── address_error_main.py │ ├── main.py │ ├── root_validator_main.py │ └── share_logic_auth_main.py └── pydantic_validator_order │ └── main.py ├── chapter06 ├── depend_class │ └── main.py ├── depend_class_more_depends │ └── main.py ├── depend_class_nest_depends │ └── main.py ├── depend_func │ └── main.py ├── depend_global_depends │ └── main.py └── depend_group_router │ └── main.py ├── chapter07 ├── base_http_middleware │ └── main.py ├── cors_middleware │ └── main.py ├── https_redirect_middleware │ └── main.py ├── log_response_middleware │ └── main.py ├── middleware_process_time │ └── main.py ├── tracdid_middleware │ └── main.py ├── trusted_host_middleware │ └── main.py └── whileIp_middleware │ └── main.py ├── chapter08 ├── aioredis_fastapi │ └── main.py ├── aioredis_lock │ └── main.py ├── aioredis_pubsub │ └── main.py ├── databases_sql │ ├── main.py │ └── user.db ├── databases_sqlalchemy │ ├── main.py │ └── user.db ├── fastapi_sqlalchemy │ ├── alembic.ini │ ├── alembic │ │ ├── README │ │ ├── env.py │ │ ├── script.py.mako │ │ └── versions │ │ │ ├── 287a3cf31b84_shann.py │ │ │ └── 3328ff109aa7_add_mobile.py │ ├── api │ │ ├── __init__.py │ │ └── user.py │ ├── config │ │ ├── __init__.py │ │ └── confiig.py │ ├── db │ │ ├── __init__.py │ │ └── database.py │ ├── dependencies │ │ └── __init__.py │ ├── main.py │ ├── models │ │ ├── __init__.py │ │ └── user.py │ ├── schemas │ │ ├── __init__.py │ │ └── user.py │ ├── servies │ │ ├── __init__.py │ │ └── user.py │ └── user.db ├── lua_register_script │ ├── 2mian.py │ └── mian.py ├── sql_model │ └── main.py ├── sqlalchemy_async_sqlite3 │ ├── aiosqlite_user.db │ └── main.py ├── sqlalchemy_sync_sqlite3 │ ├── main.py │ └── user.db ├── sqlite3_connect │ ├── main.py │ └── test.db ├── sqlmodel_async_sqlite3 │ ├── aiosqlite_user.db │ └── main.py └── sqlmodel_sync_sqlite3 │ ├── main.py │ └── user.db ├── chapter09 ├── api_key │ └── main.py ├── http_basic │ └── main.py ├── http_digest │ └── main.py ├── jwt_use │ └── main.py ├── mode_client │ └── main.py ├── mode_code │ ├── get_token.py │ └── main.py └── mode_password │ └── main.py ├── chapter10 ├── shorr_url_pro │ ├── api │ │ ├── __init__.py │ │ ├── short.py │ │ └── user.py │ ├── config │ │ ├── __init__.py │ │ └── config.py │ ├── db │ │ ├── __init__.py │ │ └── database.py │ ├── dependencies │ │ └── __init__.py │ ├── main.py │ ├── models │ │ ├── __init__.py │ │ └── model.py │ ├── schemas │ │ ├── __init__.py │ │ └── user.py │ ├── servies │ │ ├── __init__.py │ │ ├── short.py │ │ └── user.py │ ├── short.db │ └── utils │ │ └── __init__.py ├── short_url_pro │ ├── api │ │ ├── __init__.py │ │ ├── short.py │ │ └── user.py │ ├── app.py │ ├── config │ │ ├── __init__.py │ │ └── config.py │ ├── db │ │ ├── __init__.py │ │ └── database.py │ ├── dependencies │ │ └── __init__.py │ ├── main.py │ ├── models │ │ ├── __init__.py │ │ └── model.py │ ├── schemas │ │ └── __init__.py │ ├── servies │ │ ├── __init__.py │ │ ├── short.db │ │ ├── short.py │ │ └── user.py │ ├── short.db │ └── utils │ │ ├── __init__.py │ │ ├── auth_helper.py │ │ ├── passlib_hepler.py │ │ └── random_helper.py └── 测试生成模型.pdma.json ├── chapter11 ├── distributed_websocket │ ├── api │ │ ├── __init__.py │ │ ├── room.py │ │ └── user.py │ ├── app.py │ ├── chat.db │ ├── config │ │ ├── __init__.py │ │ └── config.py │ ├── db │ │ ├── __init__.py │ │ └── database.py │ ├── dependencies │ │ └── __init__.py │ ├── main.py │ ├── models │ │ ├── __init__.py │ │ └── model.py │ ├── schemas │ │ └── __init__.py │ ├── servies │ │ ├── __init__.py │ │ └── user.py │ ├── templates │ │ ├── login.html │ │ ├── register.html │ │ └── room.html │ └── utils │ │ ├── __init__.py │ │ ├── auth_helper.py │ │ ├── passlib_hepler.py │ │ ├── random_helper.py │ │ ├── room_connection_helper.py │ │ └── room_connection_helper_distributed.py └── websocket │ ├── api │ ├── __init__.py │ ├── room.py │ └── user.py │ ├── app.py │ ├── chat.db │ ├── config │ ├── __init__.py │ └── config.py │ ├── db │ ├── __init__.py │ └── database.py │ ├── dependencies │ └── __init__.py │ ├── main.py │ ├── models │ ├── __init__.py │ └── model.py │ ├── schemas │ └── __init__.py │ ├── servies │ ├── __init__.py │ └── user.py │ ├── templates │ ├── login.html │ ├── register.html │ └── room.html │ └── utils │ ├── __init__.py │ ├── auth_helper.py │ ├── passlib_hepler.py │ ├── random_helper.py │ └── room_connection_helper.py ├── chapter12 └── booking_system │ ├── __init__.py │ ├── apis │ ├── __init__.py │ ├── doctor │ │ ├── api │ │ │ ├── __init__.py │ │ │ └── doctor_api.py │ │ ├── dependencies │ │ │ └── __init__.py │ │ ├── repository │ │ │ └── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── hospital │ │ ├── __init__.py │ │ ├── api │ │ │ ├── __init__.py │ │ │ └── get_hospital_info.py │ │ └── repository │ │ │ └── __init__.py │ ├── payorders │ │ ├── __init__.py │ │ ├── api │ │ │ ├── __init__.py │ │ │ ├── doctor_order_check.py │ │ │ ├── doctor_reserve_order.py │ │ │ ├── doctor_reserve_reorder.py │ │ │ ├── payback_reserve_order.py │ │ │ └── reserve_order_info.py │ │ ├── dependencies │ │ │ └── __init__.py │ │ ├── repository │ │ │ └── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ └── userorders │ │ ├── __init__.py │ │ ├── api │ │ ├── __init__.py │ │ ├── refund_reserve_order.py │ │ ├── unpay_reserve_order.py │ │ ├── user_order_info.py │ │ ├── user_order_list.py │ │ └── wxauth_login.py │ │ ├── repository │ │ └── __init__.py │ │ └── schemas │ │ └── __init__.py │ ├── app.py │ ├── app_sync.py │ ├── config │ ├── __init__.py │ └── config.py │ ├── db │ ├── __init__.py │ ├── async_database.py │ ├── models.py │ └── sync_database.py │ ├── exts │ ├── __init__.py │ ├── async_rabbit │ │ └── __init__.py │ ├── exceptions │ │ └── __init__.py │ ├── logururoute │ │ ├── __init__.py │ │ └── config.py │ ├── rabbit │ │ └── __init__.py │ ├── rabbit2 │ │ └── __init__.py │ ├── requestvar │ │ ├── __init__.py │ │ └── bing.py │ ├── responses │ │ ├── __init__.py │ │ └── json_response.py │ └── wechatpy │ │ ├── __init__.py │ │ ├── _compat.py │ │ ├── client │ │ ├── __init__.py │ │ ├── api │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── card.py │ │ │ ├── customservice.py │ │ │ ├── datacube.py │ │ │ ├── device.py │ │ │ ├── group.py │ │ │ ├── invoice.py │ │ │ ├── jsapi.py │ │ │ ├── marketing.py │ │ │ ├── material.py │ │ │ ├── media.py │ │ │ ├── menu.py │ │ │ ├── merchant │ │ │ │ ├── __init__.py │ │ │ │ ├── category.py │ │ │ │ ├── common.py │ │ │ │ ├── express.py │ │ │ │ ├── group.py │ │ │ │ ├── order.py │ │ │ │ ├── shelf.py │ │ │ │ └── stock.py │ │ │ ├── message.py │ │ │ ├── misc.py │ │ │ ├── poi.py │ │ │ ├── qrcode.py │ │ │ ├── scan.py │ │ │ ├── semantic.py │ │ │ ├── shakearound.py │ │ │ ├── tag.py │ │ │ ├── template.py │ │ │ ├── user.py │ │ │ ├── wifi.py │ │ │ └── wxa.py │ │ └── base.py │ │ ├── component.py │ │ ├── constants.py │ │ ├── crypto │ │ ├── __init__.py │ │ ├── base.py │ │ ├── cryptography.py │ │ ├── pkcs7.py │ │ └── pycrypto.py │ │ ├── enterprise │ │ ├── __init__.py │ │ ├── client │ │ │ ├── __init__.py │ │ │ └── api │ │ │ │ ├── __init__.py │ │ │ │ ├── agent.py │ │ │ │ ├── appchat.py │ │ │ │ ├── batch.py │ │ │ │ ├── chat.py │ │ │ │ ├── department.py │ │ │ │ ├── jsapi.py │ │ │ │ ├── material.py │ │ │ │ ├── media.py │ │ │ │ ├── menu.py │ │ │ │ ├── message.py │ │ │ │ ├── misc.py │ │ │ │ ├── oauth.py │ │ │ │ ├── service.py │ │ │ │ ├── shakearound.py │ │ │ │ ├── tag.py │ │ │ │ └── user.py │ │ ├── crypto.py │ │ ├── events.py │ │ ├── exceptions.py │ │ ├── messages.py │ │ ├── parser.py │ │ └── replies.py │ │ ├── events.py │ │ ├── exceptions.py │ │ ├── fields.py │ │ ├── messages.py │ │ ├── oauth.py │ │ ├── parser.py │ │ ├── pay │ │ ├── __init__.py │ │ ├── api │ │ │ ├── __init__.py │ │ │ ├── coupon.py │ │ │ ├── jsapi.py │ │ │ ├── micropay.py │ │ │ ├── order.py │ │ │ ├── redpack.py │ │ │ ├── refund.py │ │ │ ├── tools.py │ │ │ ├── transfer.py │ │ │ └── withhold.py │ │ ├── base.py │ │ └── utils.py │ │ ├── replies.py │ │ ├── session │ │ ├── __init__.py │ │ ├── memcachedstorage.py │ │ ├── memorystorage.py │ │ ├── redisstorage.py │ │ └── shovestorage.py │ │ └── utils.py │ ├── main.py │ ├── middlewares │ ├── __init__.py │ └── loger │ │ ├── __init__.py │ │ ├── bing.py │ │ └── middleware.py │ ├── order_consumer.py │ ├── plugins │ ├── __init__.py │ ├── base.py │ └── request_hook.py │ ├── requirements.txt │ ├── static │ ├── swagger-ui-bundle.js │ └── swagger-ui.css │ ├── utils │ ├── __init__.py │ ├── cast_helper.py │ ├── datatime_helper.py │ ├── json_helper.py │ ├── ordernum_helper.py │ ├── run_with_asyncio.py │ └── xmlhelper.py │ └── wxchatsdk │ └── __init__.py ├── chapter13 ├── booking_system │ ├── __init__.py │ ├── apis │ │ ├── __init__.py │ │ ├── doctor │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ └── doctor_api.py │ │ │ ├── dependencies │ │ │ │ └── __init__.py │ │ │ ├── repository │ │ │ │ └── __init__.py │ │ │ └── schemas │ │ │ │ └── __init__.py │ │ ├── hospital │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ └── get_hospital_info.py │ │ │ └── repository │ │ │ │ └── __init__.py │ │ ├── payorders │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ ├── doctor_order_check.py │ │ │ │ ├── doctor_reserve_order.py │ │ │ │ ├── doctor_reserve_reorder.py │ │ │ │ ├── payback_reserve_order.py │ │ │ │ └── reserve_order_info.py │ │ │ ├── dependencies │ │ │ │ └── __init__.py │ │ │ ├── repository │ │ │ │ └── __init__.py │ │ │ └── schemas │ │ │ │ └── __init__.py │ │ └── userorders │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ ├── __init__.py │ │ │ ├── refund_reserve_order.py │ │ │ ├── unpay_reserve_order.py │ │ │ ├── user_order_info.py │ │ │ ├── user_order_list.py │ │ │ └── wxauth_login.py │ │ │ ├── repository │ │ │ └── __init__.py │ │ │ └── schemas │ │ │ └── __init__.py │ ├── app.py │ ├── app_sync.py │ ├── config │ │ ├── __init__.py │ │ └── config.py │ ├── db │ │ ├── __init__.py │ │ ├── async_database.py │ │ ├── models.py │ │ └── sync_database.py │ ├── exts │ │ ├── __init__.py │ │ ├── async_rabbit │ │ │ └── __init__.py │ │ ├── exceptions │ │ │ └── __init__.py │ │ ├── logururoute │ │ │ ├── __init__.py │ │ │ └── config.py │ │ ├── rabbit │ │ │ └── __init__.py │ │ ├── rabbit2 │ │ │ └── __init__.py │ │ ├── requestvar │ │ │ ├── __init__.py │ │ │ └── bing.py │ │ ├── responses │ │ │ ├── __init__.py │ │ │ └── json_response.py │ │ └── wechatpy │ │ │ ├── __init__.py │ │ │ ├── _compat.py │ │ │ ├── client │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ ├── base.py │ │ │ │ ├── card.py │ │ │ │ ├── customservice.py │ │ │ │ ├── datacube.py │ │ │ │ ├── device.py │ │ │ │ ├── group.py │ │ │ │ ├── invoice.py │ │ │ │ ├── jsapi.py │ │ │ │ ├── marketing.py │ │ │ │ ├── material.py │ │ │ │ ├── media.py │ │ │ │ ├── menu.py │ │ │ │ ├── merchant │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── category.py │ │ │ │ │ ├── common.py │ │ │ │ │ ├── express.py │ │ │ │ │ ├── group.py │ │ │ │ │ ├── order.py │ │ │ │ │ ├── shelf.py │ │ │ │ │ └── stock.py │ │ │ │ ├── message.py │ │ │ │ ├── misc.py │ │ │ │ ├── poi.py │ │ │ │ ├── qrcode.py │ │ │ │ ├── scan.py │ │ │ │ ├── semantic.py │ │ │ │ ├── shakearound.py │ │ │ │ ├── tag.py │ │ │ │ ├── template.py │ │ │ │ ├── user.py │ │ │ │ ├── wifi.py │ │ │ │ └── wxa.py │ │ │ └── base.py │ │ │ ├── component.py │ │ │ ├── constants.py │ │ │ ├── crypto │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── cryptography.py │ │ │ ├── pkcs7.py │ │ │ └── pycrypto.py │ │ │ ├── enterprise │ │ │ ├── __init__.py │ │ │ ├── client │ │ │ │ ├── __init__.py │ │ │ │ └── api │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── agent.py │ │ │ │ │ ├── appchat.py │ │ │ │ │ ├── batch.py │ │ │ │ │ ├── chat.py │ │ │ │ │ ├── department.py │ │ │ │ │ ├── jsapi.py │ │ │ │ │ ├── material.py │ │ │ │ │ ├── media.py │ │ │ │ │ ├── menu.py │ │ │ │ │ ├── message.py │ │ │ │ │ ├── misc.py │ │ │ │ │ ├── oauth.py │ │ │ │ │ ├── service.py │ │ │ │ │ ├── shakearound.py │ │ │ │ │ ├── tag.py │ │ │ │ │ └── user.py │ │ │ ├── crypto.py │ │ │ ├── events.py │ │ │ ├── exceptions.py │ │ │ ├── messages.py │ │ │ ├── parser.py │ │ │ └── replies.py │ │ │ ├── events.py │ │ │ ├── exceptions.py │ │ │ ├── fields.py │ │ │ ├── messages.py │ │ │ ├── oauth.py │ │ │ ├── parser.py │ │ │ ├── pay │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ ├── coupon.py │ │ │ │ ├── jsapi.py │ │ │ │ ├── micropay.py │ │ │ │ ├── order.py │ │ │ │ ├── redpack.py │ │ │ │ ├── refund.py │ │ │ │ ├── tools.py │ │ │ │ ├── transfer.py │ │ │ │ └── withhold.py │ │ │ ├── base.py │ │ │ └── utils.py │ │ │ ├── replies.py │ │ │ ├── session │ │ │ ├── __init__.py │ │ │ ├── memcachedstorage.py │ │ │ ├── memorystorage.py │ │ │ ├── redisstorage.py │ │ │ └── shovestorage.py │ │ │ └── utils.py │ ├── main.py │ ├── middlewares │ │ ├── __init__.py │ │ └── loger │ │ │ ├── __init__.py │ │ │ ├── bing.py │ │ │ └── middleware.py │ ├── order_consumer.py │ ├── plugins │ │ ├── __init__.py │ │ ├── base.py │ │ └── request_hook.py │ ├── requirements.txt │ ├── static │ │ ├── swagger-ui-bundle.js │ │ └── swagger-ui.css │ ├── testcase │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_async_api_v1.py │ │ ├── test_async_api_v2.py │ │ └── test_sync_api.py │ ├── utils │ │ ├── __init__.py │ │ ├── cast_helper.py │ │ ├── datatime_helper.py │ │ ├── json_helper.py │ │ ├── ordernum_helper.py │ │ ├── run_with_asyncio.py │ │ └── xmlhelper.py │ └── wxchatsdk │ │ └── __init__.py ├── pytest_demo │ ├── cast_helper.py │ └── test_add.py ├── pytest_fixture_demo │ ├── testcase │ │ ├── conftest.py │ │ └── test_case1.py │ └── tests │ │ ├── __init__.py │ │ ├── test_fixs.py │ │ ├── test_fixs_parametrize.py │ │ ├── test_fixs_parametrize_class.py │ │ └── test_fixs_params.py └── unittest_demo │ └── main.py ├── chapter14 ├── app.ini ├── booking_system │ ├── .drone.yml │ ├── Dockerfile │ ├── __init__.py │ ├── apis │ │ ├── __init__.py │ │ ├── doctor │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ └── doctor_api.py │ │ │ ├── dependencies │ │ │ │ └── __init__.py │ │ │ ├── repository │ │ │ │ └── __init__.py │ │ │ └── schemas │ │ │ │ └── __init__.py │ │ ├── hospital │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ └── get_hospital_info.py │ │ │ └── repository │ │ │ │ └── __init__.py │ │ ├── payorders │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ ├── doctor_order_check.py │ │ │ │ ├── doctor_reserve_order.py │ │ │ │ ├── doctor_reserve_reorder.py │ │ │ │ ├── payback_reserve_order.py │ │ │ │ └── reserve_order_info.py │ │ │ ├── dependencies │ │ │ │ └── __init__.py │ │ │ ├── repository │ │ │ │ └── __init__.py │ │ │ └── schemas │ │ │ │ └── __init__.py │ │ └── userorders │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ ├── __init__.py │ │ │ ├── refund_reserve_order.py │ │ │ ├── unpay_reserve_order.py │ │ │ ├── user_order_info.py │ │ │ ├── user_order_list.py │ │ │ └── wxauth_login.py │ │ │ ├── repository │ │ │ └── __init__.py │ │ │ └── schemas │ │ │ └── __init__.py │ ├── app.py │ ├── app_sync.py │ ├── config │ │ ├── __init__.py │ │ └── config.py │ ├── db │ │ ├── __init__.py │ │ ├── async_database.py │ │ ├── models.py │ │ └── sync_database.py │ ├── docker-compose.yml │ ├── exts │ │ ├── __init__.py │ │ ├── async_rabbit │ │ │ └── __init__.py │ │ ├── exceptions │ │ │ └── __init__.py │ │ ├── logururoute │ │ │ ├── __init__.py │ │ │ └── config.py │ │ ├── rabbit │ │ │ └── __init__.py │ │ ├── rabbit2 │ │ │ └── __init__.py │ │ ├── requestvar │ │ │ ├── __init__.py │ │ │ └── bing.py │ │ ├── responses │ │ │ ├── __init__.py │ │ │ └── json_response.py │ │ └── wechatpy │ │ │ ├── __init__.py │ │ │ ├── _compat.py │ │ │ ├── client │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ ├── base.py │ │ │ │ ├── card.py │ │ │ │ ├── customservice.py │ │ │ │ ├── datacube.py │ │ │ │ ├── device.py │ │ │ │ ├── group.py │ │ │ │ ├── invoice.py │ │ │ │ ├── jsapi.py │ │ │ │ ├── marketing.py │ │ │ │ ├── material.py │ │ │ │ ├── media.py │ │ │ │ ├── menu.py │ │ │ │ ├── merchant │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── category.py │ │ │ │ │ ├── common.py │ │ │ │ │ ├── express.py │ │ │ │ │ ├── group.py │ │ │ │ │ ├── order.py │ │ │ │ │ ├── shelf.py │ │ │ │ │ └── stock.py │ │ │ │ ├── message.py │ │ │ │ ├── misc.py │ │ │ │ ├── poi.py │ │ │ │ ├── qrcode.py │ │ │ │ ├── scan.py │ │ │ │ ├── semantic.py │ │ │ │ ├── shakearound.py │ │ │ │ ├── tag.py │ │ │ │ ├── template.py │ │ │ │ ├── user.py │ │ │ │ ├── wifi.py │ │ │ │ └── wxa.py │ │ │ └── base.py │ │ │ ├── component.py │ │ │ ├── constants.py │ │ │ ├── crypto │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── cryptography.py │ │ │ ├── pkcs7.py │ │ │ └── pycrypto.py │ │ │ ├── enterprise │ │ │ ├── __init__.py │ │ │ ├── client │ │ │ │ ├── __init__.py │ │ │ │ └── api │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── agent.py │ │ │ │ │ ├── appchat.py │ │ │ │ │ ├── batch.py │ │ │ │ │ ├── chat.py │ │ │ │ │ ├── department.py │ │ │ │ │ ├── jsapi.py │ │ │ │ │ ├── material.py │ │ │ │ │ ├── media.py │ │ │ │ │ ├── menu.py │ │ │ │ │ ├── message.py │ │ │ │ │ ├── misc.py │ │ │ │ │ ├── oauth.py │ │ │ │ │ ├── service.py │ │ │ │ │ ├── shakearound.py │ │ │ │ │ ├── tag.py │ │ │ │ │ └── user.py │ │ │ ├── crypto.py │ │ │ ├── events.py │ │ │ ├── exceptions.py │ │ │ ├── messages.py │ │ │ ├── parser.py │ │ │ └── replies.py │ │ │ ├── events.py │ │ │ ├── exceptions.py │ │ │ ├── fields.py │ │ │ ├── messages.py │ │ │ ├── oauth.py │ │ │ ├── parser.py │ │ │ ├── pay │ │ │ ├── __init__.py │ │ │ ├── api │ │ │ │ ├── __init__.py │ │ │ │ ├── coupon.py │ │ │ │ ├── jsapi.py │ │ │ │ ├── micropay.py │ │ │ │ ├── order.py │ │ │ │ ├── redpack.py │ │ │ │ ├── refund.py │ │ │ │ ├── tools.py │ │ │ │ ├── transfer.py │ │ │ │ └── withhold.py │ │ │ ├── base.py │ │ │ └── utils.py │ │ │ ├── replies.py │ │ │ ├── session │ │ │ ├── __init__.py │ │ │ ├── memcachedstorage.py │ │ │ ├── memorystorage.py │ │ │ ├── redisstorage.py │ │ │ └── shovestorage.py │ │ │ └── utils.py │ ├── main.py │ ├── middlewares │ │ ├── __init__.py │ │ └── loger │ │ │ ├── __init__.py │ │ │ ├── bing.py │ │ │ └── middleware.py │ ├── order_consumer.py │ ├── plugins │ │ ├── __init__.py │ │ ├── base.py │ │ └── request_hook.py │ ├── requirements.txt │ ├── static │ │ ├── swagger-ui-bundle.js │ │ └── swagger-ui.css │ ├── testcase │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_async_api_v1.py │ │ ├── test_async_api_v2.py │ │ └── test_sync_api.py │ ├── utils │ │ ├── __init__.py │ │ ├── cast_helper.py │ │ ├── datatime_helper.py │ │ ├── json_helper.py │ │ ├── ordernum_helper.py │ │ ├── run_with_asyncio.py │ │ └── xmlhelper.py │ └── wxchatsdk │ │ └── __init__.py └── drone_docker-compose.yml ├── chapter15 ├── Fastapi_cProfile │ ├── .prof │ └── main.py ├── Jaeger │ ├── test_jaeger_client │ │ └── main.py │ └── test_jaeger_client_fastapi │ │ └── middeware │ │ ├── __init__.py │ │ └── main.py ├── async_sync_change │ ├── main_asgiref_async_to_sync.py │ ├── main_asgiref_sync_to_async.py │ ├── main_asyncer_asyncify.py │ └── main_asyncer_syncify.py ├── async_wrapper │ ├── .runtest.prof │ └── main_asgiref_sync_to_async.py ├── body │ ├── main_01.py │ ├── main_02.py │ ├── main_03.py │ └── main_04.py ├── cProfile │ ├── c_profile_text_run.py │ ├── crpresutl.svg │ ├── runtest.prof │ ├── runtest_profile.stats │ └── runtest_profile_stats_run.py ├── contextvar_request │ ├── bind_.py │ ├── main_class.py │ └── request.py ├── depends │ ├── main_class.py │ ├── main_class_call.py │ ├── main_class_security_scopes.py │ ├── main_fun.py │ └── main_fun_security_scopes.py ├── fastapi_cache │ ├── main.py │ └── uu.py ├── model_sort │ └── main_asyncer_syncify.py ├── plugins │ ├── base.py │ └── main.py ├── sentry │ ├── __init__.py │ └── main.py └── smtplib │ ├── main_aiosmtplib.py │ ├── main_smtplib.py │ ├── test.jpg │ ├── test1.txt │ └── test2.txt └── chapter16 ├── Jaeger ├── test_jaeger_client │ └── main.py └── test_jaeger_client_fastapi │ └── middeware │ ├── __init__.py │ └── main.py ├── async_sync_change ├── main_asgiref_async_to_sync.py ├── main_asgiref_sync_to_async.py ├── main_asyncer_asyncify.py └── main_asyncer_syncify.py ├── async_wrapper ├── .runtest.prof └── main_asgiref_sync_to_async.py ├── body ├── main_01.py ├── main_02.py ├── main_03.py └── main_04.py ├── contextvar_request ├── bind_.py ├── main_class.py └── request.py ├── depends ├── main_class.py ├── main_class_call.py ├── main_class_security_scopes.py ├── main_fun.py └── main_fun_security_scopes.py ├── model_sort └── main_asyncer_syncify.py ├── plugins ├── base.py └── main.py ├── sentry ├── __init__.py └── main.py └── smtplib ├── aaaa.py ├── main_aiosmtplib.py ├── main_smtplib.py ├── test.jpg ├── test1.txt └── test2.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .diea/ 3 | .DS_Store 4 | __pycache__/ 5 | *.py[cod] 6 | 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 zyx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter01/asyncio/contrast_sync.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | 4 | def take_up_time(func): 5 | def wrapper(*args, **kwargs): 6 | print("开始执行---->") 7 | now = time.time() 8 | result = func(*args, **kwargs) 9 | using = (time.time() - now) * 1000 10 | print(f"结束执行,消耗时间为:{using}ms") 11 | return result 12 | return wrapper 13 | 14 | def request_sync(url): 15 | response = requests.get(url) 16 | return response 17 | 18 | @take_up_time 19 | def run(): 20 | for i in range(0, 50): 21 | request_sync('https://www.baidu.com') 22 | 23 | 24 | if __name__ == '__main__': 25 | run() -------------------------------------------------------------------------------- /chapter01/asyncio/cotrast_async.py: -------------------------------------------------------------------------------- 1 | import aiohttp, asyncio, time 2 | 3 | 4 | def take_up_time(func): 5 | def wrapper(*args, **kwargs): 6 | print("开始执行---->") 7 | now = time.time() 8 | result = func(*args, **kwargs) 9 | using = (time.time() - now) * 1000 10 | print(f"结束执行,消耗时间为:{using}ms") 11 | return result 12 | 13 | return wrapper 14 | 15 | 16 | async def request_async(): 17 | async with aiohttp.ClientSession() as session: 18 | async with session.get('https://www.baidu.com') as resp: 19 | pass 20 | 21 | 22 | @take_up_time 23 | def run(): 24 | tasks = [asyncio.ensure_future(request_async()) for x in range(0, 49)] 25 | loop = asyncio.get_event_loop() 26 | tasks = asyncio.gather(*tasks) 27 | loop.run_until_complete(tasks) 28 | 29 | 30 | if __name__ == '__main__': 31 | run() 32 | -------------------------------------------------------------------------------- /chapter02/static/css/style.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter02/static/css/style.css -------------------------------------------------------------------------------- /chapter02/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 你好,欢迎您学习Fastapi框架! 10 | 11 | 12 |
13 |

14 | 你好!欢迎您学习Fastapi框架! 15 |

16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /chapter02/templates/yyy.txt: -------------------------------------------------------------------------------- 1 | asas 2 | sadas 3 | sadasd 4 | sdasd 5 | asdasd -------------------------------------------------------------------------------- /chapter03/async_sync/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | import threading 6 | import time 7 | import asyncio 8 | app = FastAPI(routes=None) 9 | 10 | @app.get(path="/async") 11 | async def asyncdef(): 12 | await asyncio.sleep(10) 13 | print("当前协程运行的线程ID:", threading.current_thread().ident) 14 | return {"index": "async"} 15 | 16 | @app.get(path="/sync") 17 | def syncdef(): 18 | time.sleep(10) 19 | print("当前普通函数运行的线程ID:",threading.current_thread().ident) 20 | return {"index": "sync"} 21 | 22 | 23 | 24 | 25 | if __name__ == "__main__": 26 | import uvicorn 27 | import os 28 | 29 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 30 | print(app_modeel_name) 31 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 32 | -------------------------------------------------------------------------------- /chapter03/background_tasks/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | from starlette.background import BackgroundTasks 6 | import time 7 | app = FastAPI(routes=None) 8 | import asyncio 9 | def send_mail(n): 10 | time.sleep(n) 11 | 12 | @app.api_route(path="/index", methods=["GET", "POST"]) 13 | async def index(tasks: BackgroundTasks): 14 | tasks.add_task(send_mail, 10) 15 | print(id(asyncio.get_event_loop())) 16 | return {"index": "index"} 17 | 18 | if __name__ == "__main__": 19 | import uvicorn 20 | import os 21 | 22 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 23 | print(app_modeel_name) 24 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 25 | -------------------------------------------------------------------------------- /chapter03/close_docs/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | app = FastAPI( 6 | docs_url=None, 7 | redoc_url=None, 8 | # 或者直接设置openapi_url=None 9 | openapi_url=None, 10 | ) 11 | if __name__ == "__main__": 12 | import uvicorn 13 | import os 14 | 15 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 16 | print(app_modeel_name) 17 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 18 | -------------------------------------------------------------------------------- /chapter03/configparser_config/conf.ini: -------------------------------------------------------------------------------- 1 | [fastapi_config] 2 | debug = True 3 | title = "FastAPI" 4 | description = "FastAPI文档明细描述" 5 | version = v1.0.0 6 | 7 | [redis] 8 | ip = 127.0.0.1 9 | port = 6379 10 | password = 123456 -------------------------------------------------------------------------------- /chapter03/configparser_config/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | import configparser 6 | 7 | config = configparser.ConfigParser() 8 | config.read('conf.ini', encoding='utf-8') 9 | 10 | app = FastAPI( 11 | debug=bool(config.get('fastapi_config', 'debug')), 12 | title=config.get('fastapi_config', 'title'), 13 | description=config.get('fastapi_config', 'description'), 14 | version=config.get('fastapi_config', 'version'), 15 | ) 16 | 17 | if __name__ == "__main__": 18 | import uvicorn 19 | import os 20 | 21 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 22 | print(app_modeel_name) 23 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 24 | -------------------------------------------------------------------------------- /chapter03/debugshow/main.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter03/debugshow/main.py -------------------------------------------------------------------------------- /chapter03/env_config/.env: -------------------------------------------------------------------------------- 1 | DEBUG=true 2 | TITLE="FastAPI" 3 | DESCRIPTION="FastAPI文档明细描述" 4 | vERSION="v1.0.0" -------------------------------------------------------------------------------- /chapter03/global_exception/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | from starlette.responses import JSONResponse 6 | 7 | async def exception_not_found(request, exc): 8 | return JSONResponse({ 9 | "code": exc.status_code, 10 | "error": "没有定义这个请求地址"}, 11 | status_code=exc.status_code) 12 | 13 | exception_handlers = { 14 | 404: exception_not_found, 15 | } 16 | 17 | app = FastAPI(exception_handlers=exception_handlers) 18 | 19 | 20 | if __name__ == "__main__": 21 | import uvicorn 22 | import os 23 | 24 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 25 | print(app_modeel_name) 26 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 27 | -------------------------------------------------------------------------------- /chapter03/more_routers/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | from starlette.responses import JSONResponse 6 | 7 | app = FastAPI() 8 | 9 | # ============多重URL地址绑定函数============ 10 | # ========================================= 11 | @app.get('/', response_class=JSONResponse) 12 | @app.get('/index', response_class=JSONResponse) 13 | @app.post('/index', response_class=JSONResponse) 14 | @app.get("/app/hello", tags=['app实例对象注册接口-示例']) 15 | def app_hello(): 16 | return {"Hello": "app api"} 17 | 18 | # ============同一个URL动态和静态路由========== 19 | # ========================================= 20 | # 动态路由 21 | @app.get('/user/{userid}') 22 | async def login(userid: str): 23 | return {"Hello": "dynamic"} 24 | 25 | 26 | # 静态路由 27 | @app.get('/user/userid') 28 | async def login(): 29 | return {"Hello": "static"} 30 | 31 | 32 | 33 | 34 | if __name__ == "__main__": 35 | import uvicorn 36 | import os 37 | 38 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 39 | print(app_modeel_name) 40 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 41 | -------------------------------------------------------------------------------- /chapter03/mount_app/fastapiapp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | from fastapi.responses import JSONResponse 6 | 7 | app = FastAPI(title='主应用',description="我是主应用文档的描述",version="v1.0.0") 8 | @app.get('/index',summary='首页') 9 | async def index(): 10 | return JSONResponse({"index": "我是属于主应用的接口!"}) 11 | 12 | subapp = FastAPI(title='子应用',description="我是子应用文档的描述",version="v1.0.0") 13 | @subapp.get('/index',summary='首页') 14 | async def index(): 15 | return JSONResponse({"index": "我是属于子应用的接口!"}) 16 | 17 | app.mount(path='/subapp',app=subapp,name='subapp') 18 | 19 | 20 | if __name__ == "__main__": 21 | import uvicorn 22 | import os 23 | 24 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 25 | print(app_modeel_name) 26 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 27 | -------------------------------------------------------------------------------- /chapter03/mount_app/flaskapp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | from fastapi.responses import JSONResponse 6 | 7 | app = FastAPI(title='主应用',description="我是主应用文档的描述",version="v1.0.0") 8 | @app.get('/index',summary='首页') 9 | async def index(): 10 | return JSONResponse({"index": "我是属于主应用的接口!"}) 11 | 12 | subapp = FastAPI(title='子应用',description="我是子应用文档的描述",version="v1.0.0") 13 | @subapp.get('/index',summary='首页') 14 | async def index(): 15 | return JSONResponse({"index": "我是属于子应用的接口!"}) 16 | 17 | app.mount(path='/subapp',app=subapp,name='subapp') 18 | 19 | 20 | if __name__ == "__main__": 21 | import uvicorn 22 | import os 23 | 24 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 25 | print(app_modeel_name) 26 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 27 | -------------------------------------------------------------------------------- /chapter03/parameter_cookie/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import List, Optional, Set 4 | from fastapi import FastAPI, Query, Path, Body, Header, Cookie 5 | from starlette import status 6 | from enum import Enum 7 | 8 | from starlette.responses import Response 9 | 10 | app = FastAPI() 11 | 12 | 13 | @app.get("/set_cookie/") 14 | def setcookie(response: Response): 15 | response.set_cookie(key="xiaozhong", value="chengxuyuan-xiaozhongtongxue") 16 | return 'set_cookie ok!' 17 | 18 | @app.get("/get_cookie") 19 | async def Cookier_handel(xiaozhong: Optional[str] = Cookie(None)): 20 | return { 21 | 'xiaozhong':xiaozhong 22 | } 23 | 24 | if __name__ == "__main__": 25 | import uvicorn 26 | import os 27 | 28 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 29 | print(app_modeel_name) 30 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 31 | -------------------------------------------------------------------------------- /chapter03/parameter_form_and_file/data.bat: -------------------------------------------------------------------------------- 1 | 你好,我是小钟同学。 -------------------------------------------------------------------------------- /chapter03/parameter_request/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import List, Optional, Set 4 | from fastapi import FastAPI, Query, Path, Body, Header, Cookie 5 | from starlette import status 6 | from enum import Enum 7 | 8 | from starlette.responses import Response 9 | from fastapi import Request 10 | 11 | app = FastAPI() 12 | 13 | 14 | @app.get("/get_request/") 15 | async def get_request(request: Request): 16 | form_data= await request.form() 17 | body_data = await request.body() 18 | return { 19 | 'url':request.url, 20 | 'base_url': request.base_url, 21 | 'client_host ': request.client.host, 22 | 'query_params': request.query_params, 23 | 'json_data':await request.json() if body_data else None, 24 | 'form_data':form_data, 25 | 'body_data': body_data, 26 | } 27 | 28 | if __name__ == "__main__": 29 | import uvicorn 30 | import os 31 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 32 | print(app_modeel_name) 33 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 34 | -------------------------------------------------------------------------------- /chapter03/parameter_response/data.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter03/parameter_response/data.bat -------------------------------------------------------------------------------- /chapter03/parameter_response/main_html_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import List, Optional, Set 4 | from fastapi import FastAPI, Query, Path, Body, Header, Cookie 5 | from starlette import status 6 | from enum import Enum 7 | 8 | from starlette.responses import Response, JSONResponse 9 | from fastapi import Request 10 | 11 | app = FastAPI() 12 | 13 | 14 | from fastapi.responses import HTMLResponse 15 | 16 | def generate_html_response(): 17 | html_content = """ 18 | 19 | 20 | Fastapi框架学习 21 | 22 | 23 |

欢迎学习Fastapi框架!

24 | 25 | 26 | """ 27 | return HTMLResponse(content=html_content, status_code=200) 28 | 29 | @app.get("/", response_class=HTMLResponse) 30 | async def index(): 31 | return generate_html_response() 32 | 33 | if __name__ == "__main__": 34 | import uvicorn 35 | import os 36 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 37 | print(app_modeel_name) 38 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 39 | -------------------------------------------------------------------------------- /chapter03/parameter_response/main_json_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import List, Optional, Set 4 | from fastapi import FastAPI, Query, Path, Body, Header, Cookie 5 | from starlette import status 6 | from enum import Enum 7 | 8 | from starlette.responses import Response, JSONResponse 9 | from fastapi import Request 10 | 11 | app = FastAPI() 12 | 13 | 14 | 15 | @app.post("/api/v1/json1/") 16 | async def index(): 17 | # 默认返回类型就是JSONResponse 18 | return {"code": 0, "msg": "ok", "data": None} 19 | 20 | @app.post("/api/v1/json2/") 21 | async def index(): 22 | return JSONResponse(status_code=404, content={"code": 0, "msg": "ok", "data": None}) 23 | 24 | if __name__ == "__main__": 25 | import uvicorn 26 | import os 27 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 28 | print(app_modeel_name) 29 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 30 | -------------------------------------------------------------------------------- /chapter03/parameter_response/main_plain_text_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import List, Optional, Set 4 | from fastapi import FastAPI, Query, Path, Body, Header, Cookie 5 | from starlette import status 6 | from enum import Enum 7 | 8 | from starlette.responses import Response, JSONResponse, PlainTextResponse 9 | from fastapi import Request 10 | 11 | app = FastAPI() 12 | 13 | 14 | 15 | @app.post("/api/v1/text1/") 16 | async def index(): 17 | return 'ok' 18 | 19 | @app.post("/api/v1/text2/") 20 | async def index(): 21 | return PlainTextResponse(status_code=404, content='ok') 22 | 23 | if __name__ == "__main__": 24 | import uvicorn 25 | import os 26 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 27 | print(app_modeel_name) 28 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 29 | -------------------------------------------------------------------------------- /chapter03/parameter_response/main_redirect_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | 6 | from starlette.responses import HTMLResponse, RedirectResponse 7 | 8 | 9 | app = FastAPI() 10 | 11 | 12 | 13 | @app.get("/baidu", response_class=HTMLResponse) 14 | async def index(): 15 | # 外部地址重定向 16 | return RedirectResponse("https://wwww.baidu.com") 17 | 18 | @app.get("/redirect1") 19 | async def index(): 20 | # 内部地址重定向 21 | return RedirectResponse("/index",status_code=301) 22 | 23 | 24 | @app.get("/redirect2") 25 | async def index(): 26 | # 内部地址重定向 27 | return RedirectResponse("/index",status_code=302) 28 | 29 | @app.get("/index") 30 | async def index(): 31 | return { 32 | 'code':200, 33 | 'messgaee':'重定向成功' 34 | } 35 | 36 | if __name__ == "__main__": 37 | import uvicorn 38 | import os 39 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 40 | print(app_modeel_name) 41 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 42 | -------------------------------------------------------------------------------- /chapter03/parameter_response/main_xml_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import List, Optional, Set 4 | from fastapi import FastAPI, Query, Path, Body, Header, Cookie 5 | from starlette import status 6 | from enum import Enum 7 | 8 | from starlette.responses import Response 9 | from fastapi import Request 10 | 11 | app = FastAPI() 12 | 13 | @app.get("/xml/") 14 | def get_xml_data(): 15 | data = """ 16 | 17 | George 18 | John 19 | Reminder 20 | Don't forget the meeting! 21 | 22 | """ 23 | return Response(content=data, media_type="application/xml") 24 | 25 | if __name__ == "__main__": 26 | import uvicorn 27 | import os 28 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 29 | print(app_modeel_name) 30 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 31 | -------------------------------------------------------------------------------- /chapter03/startup_shutdown/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | 4 | from fastapi import FastAPI 5 | from starlette.background import BackgroundTasks 6 | import time 7 | 8 | app = FastAPI() 9 | 10 | # 生命周期异步上下文管理器处理程序代替单独的启动和关闭处理程序 11 | @app.on_event("startup") 12 | async def startup_event_async(): 13 | print("服务进程启动成功-async函数") 14 | 15 | @app.on_event("startup") 16 | def startup_event_sync(): 17 | print("服务进程启动成功-sync函数") 18 | 19 | @app.on_event("shutdown") 20 | async def shutdown_event_async(): 21 | print("服务进程已关闭-async函数") 22 | 23 | 24 | @app.on_event("shutdown") 25 | def shutdown_event_sync(): 26 | print("服务进程已关闭-sync函数") 27 | 28 | if __name__ == "__main__": 29 | import uvicorn 30 | import os 31 | 32 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 33 | print(app_modeel_name) 34 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 35 | -------------------------------------------------------------------------------- /chapter04/custom_exception/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from fastapi import Request 4 | from fastapi import FastAPI, Query, HTTPException 5 | from starlette.responses import JSONResponse 6 | 7 | app = FastAPI() 8 | 9 | 10 | class CustomException(Exception): 11 | def __init__(self, message: str): 12 | self.message = message 13 | 14 | 15 | @app.exception_handler(CustomException) 16 | async def custom_exception_handler(request: Request, exc: CustomException): 17 | return JSONResponse(content={"message": exc.message}, ) 18 | 19 | 20 | @app.get("/custom_exception") 21 | async def read_unicorn(name: str = 'zhong'): 22 | if name == "zhong": 23 | raise CustomException(message='抛出自定义异常') 24 | return {"name": name} 25 | 26 | 27 | if __name__ == "__main__": 28 | import uvicorn 29 | import os 30 | 31 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 32 | print(app_modeel_name) 33 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 34 | -------------------------------------------------------------------------------- /chapter04/request_validation_error/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from fastapi import Request 4 | from fastapi import FastAPI, Query, HTTPException 5 | from fastapi.exceptions import RequestValidationError 6 | from starlette.responses import JSONResponse 7 | from fastapi import FastAPI, WebSocket, WebSocketDisconnect 8 | 9 | app = FastAPI() 10 | 11 | @app.exception_handler(RequestValidationError) 12 | async def validation_exception_handler(request, exc): 13 | return JSONResponse({'mes':'触发了RequestValidationError错误,,错误信息:%s !'%(str(exc))}) 14 | 15 | 16 | @app.get("/request_exception/") 17 | async def request_exception(user_id: int): 18 | return {"user_id": user_id} 19 | 20 | 21 | @app.websocket("/ws/{user}") 22 | async def websocket_endpoint(websocket: WebSocket, user: str): 23 | pass 24 | websocket.query_params 25 | 26 | if __name__ == "__main__": 27 | import uvicorn 28 | import os 29 | 30 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 31 | print(app_modeel_name) 32 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 33 | -------------------------------------------------------------------------------- /chapter05/pydantic_field/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from decimal import Decimal 4 | from typing import Union, Optional, List 5 | 6 | from pydantic import BaseModel, Field 7 | 8 | 9 | class User(BaseModel): 10 | name: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo") 11 | age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12) 12 | password: str = Field(..., title='密码', description='密码需要长度大于6', gl=6, example=6) 13 | tax: Optional[float] = Field(None, example=3.2) 14 | 15 | if __name__ == '__main__': 16 | user=User(name='xiaozhong',age=18,password='xxxxxxxxxxx') 17 | print(user.name) 18 | print(user.age) 19 | print(user.password) 20 | -------------------------------------------------------------------------------- /chapter05/pydantic_validator/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import Union, Optional, List 4 | 5 | from pydantic import BaseModel, validator, ValidationError 6 | 7 | 8 | class Person(BaseModel): 9 | username: str 10 | password: str 11 | 12 | # '*' 在这里是匹配任意字段 13 | @validator('*', pre=True) 14 | def split(cls, v,): 15 | """如果传参是字符串,根据逗号切割成list""" 16 | if isinstance(v, str): 17 | return v.split(',') 18 | return v 19 | 20 | 21 | if __name__ == '__main__': 22 | try: 23 | user = Person(username='xiaozhong', password='123456') 24 | except ValidationError as e: 25 | print(e.errors()) 26 | print(e.json()) 27 | else: 28 | print(user.username, user.password) 29 | -------------------------------------------------------------------------------- /chapter05/pydantic_validator/root_validator_main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import Dict 4 | 5 | from pydantic import BaseModel, validator, ValidationError, PydanticValueError 6 | 7 | from pydantic import BaseModel, ValidationError, root_validator 8 | 9 | 10 | class User(BaseModel): 11 | username: str 12 | password_old: str 13 | password_new: str 14 | 15 | @root_validator 16 | def check_passwords(cls, values): 17 | password_old, password_new = values.get('password_old'), values.get('password_new') 18 | # 新旧号码的确认匹配处理 19 | if password_old and password_new and password_old != password_new: 20 | raise ValueError('passwords do not match') 21 | return values 22 | 23 | if __name__ == '__main__': 24 | try: 25 | user = User(username='xiaozhong', password_old='123456', password_new='123456_') 26 | except ValidationError as e: 27 | print(e.errors()) 28 | else: 29 | print(user.username, user.password_old) 30 | -------------------------------------------------------------------------------- /chapter05/pydantic_validator/share_logic_auth_main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import Union, Optional, List 4 | 5 | from pydantic import BaseModel, validator, ValidationError 6 | 7 | from pydantic import BaseModel, validator 8 | 9 | 10 | def share_logic_auth(name: str) -> str: 11 | if name == "xiaozhong": 12 | return "通过" 13 | return "不通过" 14 | 15 | 16 | class Base(BaseModel): 17 | name: str 18 | # 定义校验器 19 | _validator_name = validator("name", allow_reuse=True)(share_logic_auth) 20 | 21 | 22 | class Yuser(Base): 23 | pass 24 | 25 | 26 | class Xuser(Base): 27 | pass 28 | 29 | 30 | yuser = Yuser(name='xiaozhong') 31 | print("xiaozhong:名字",yuser.name) 32 | xuser = Xuser(name='_xiao') 33 | print("_xiao:名字",xuser.name) 34 | 35 | -------------------------------------------------------------------------------- /chapter05/pydantic_validator_order/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | from typing import Dict 4 | 5 | from pydantic import BaseModel, validator, ValidationError 6 | 7 | 8 | class Person(BaseModel): 9 | username: str 10 | address: Dict 11 | 12 | @validator("address",pre=True) 13 | def adress_rule(cls, address): 14 | # 如果地址长度小于6,那么则返回 15 | if len(address) < 6: 16 | raise ValueError("地址长度不能小于6") 17 | elif len(address) > 12: 18 | raise ValueError("地址长度不能大于12") 19 | return address 20 | 21 | if __name__ == '__main__': 22 | try: 23 | user = Person(username='xiaozhong', address='12345') 24 | except ValidationError as e: 25 | print(e.errors()) 26 | else: 27 | print(user.username, user.address) -------------------------------------------------------------------------------- /chapter06/depend_class/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Request, Body 2 | from fastapi import Query, Depends 3 | from fastapi.exceptions import HTTPException 4 | 5 | from fastapi import FastAPI 6 | from fastapi import Query, Depends 7 | from fastapi.exceptions import HTTPException 8 | 9 | 10 | app = FastAPI() 11 | 12 | class UsernameCheck: 13 | def __init__(self, username:str=Query(...)): 14 | if username != 'zhong': 15 | raise HTTPException(status_code=403, detail="没有权限访问") 16 | self.username = username 17 | 18 | 19 | @app.get("/user/login/") 20 | def user_login(username: UsernameCheck = Depends(UsernameCheck)): 21 | return username 22 | 23 | 24 | @app.get("/user/info") 25 | def user_info(username: UsernameCheck = Depends(UsernameCheck)): 26 | return username 27 | 28 | 29 | if __name__ == "__main__": 30 | import uvicorn 31 | import os 32 | 33 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 34 | print(app_modeel_name) 35 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 36 | -------------------------------------------------------------------------------- /chapter06/depend_func/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Request, Body 2 | from fastapi import Query, Depends 3 | from fastapi.exceptions import HTTPException 4 | 5 | from fastapi import FastAPI 6 | from fastapi import Query, Depends 7 | from fastapi.exceptions import HTTPException 8 | 9 | 10 | app = FastAPI() 11 | 12 | def username_check(username:str=Query(...)): 13 | if username != 'zhong': 14 | raise HTTPException(status_code=403, detail="没有权限访问") 15 | return username 16 | 17 | 18 | @app.get("/user/login/") 19 | def user_login(username: str = Depends(username_check)): 20 | return username 21 | 22 | 23 | @app.get("/user/info") 24 | def user_info(username: str = Depends(username_check)): 25 | return username 26 | 27 | 28 | if __name__ == "__main__": 29 | import uvicorn 30 | import os 31 | 32 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 33 | print(app_modeel_name) 34 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 35 | -------------------------------------------------------------------------------- /chapter07/cors_middleware/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | 4 | app = FastAPI() 5 | 6 | origins = [ 7 | "http://localhost.baidu.com", 8 | "https://localhost.qq.com", 9 | "http://localhost", 10 | "http://localhost:8080", 11 | ] 12 | 13 | # 添加自定义中间件 14 | app.add_middleware( 15 | CORSMiddleware, 16 | allow_origins=origins, 17 | allow_credentials=True, 18 | allow_methods=["*"], 19 | allow_headers=["*"], 20 | ) 21 | 22 | 23 | @app.get("/") 24 | async def main(): 25 | return {"message": "Hello World"} 26 | 27 | 28 | 29 | if __name__ == "__main__": 30 | import uvicorn 31 | import os 32 | 33 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 34 | print(app_modeel_name) 35 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 36 | -------------------------------------------------------------------------------- /chapter07/https_redirect_middleware/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware 4 | 5 | app = FastAPI() 6 | 7 | 8 | app.add_middleware(HTTPSRedirectMiddleware) 9 | 10 | @app.get("/index") 11 | async def httpsredirec(): 12 | return { 13 | 'code':200 14 | } 15 | 16 | 17 | if __name__ == "__main__": 18 | import uvicorn 19 | import os 20 | 21 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 22 | print(app_modeel_name) 23 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 24 | -------------------------------------------------------------------------------- /chapter07/middleware_process_time/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Request 2 | import time 3 | 4 | app = FastAPI() 5 | 6 | 7 | @app.middleware("http") 8 | async def add_process_time_header(request: Request, call_next): 9 | # 定义请求处理时间 10 | start_time = time.time() 11 | response = await call_next(request) 12 | process_time = time.time() - start_time 13 | # 添加响应头 14 | response.headers["X-Process-Time"] = str(process_time) 15 | return response 16 | 17 | 18 | @app.get("/index") 19 | async def index(): 20 | return { 21 | 'code': 200 22 | } 23 | 24 | 25 | if __name__ == "__main__": 26 | import uvicorn 27 | import os 28 | 29 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 30 | print(app_modeel_name) 31 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 32 | -------------------------------------------------------------------------------- /chapter07/trusted_host_middleware/main.py: -------------------------------------------------------------------------------- 1 | from fastapi.middleware.trustedhost import TrustedHostMiddleware 2 | from fastapi import FastAPI 3 | from starlette.middleware.gzip import GZipMiddleware 4 | 5 | app = FastAPI() 6 | 7 | app.add_middleware(TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]) 8 | 9 | @app.get("/index") 10 | async def truste(): 11 | return { 12 | 'code':200 13 | } 14 | 15 | from fastapi import FastAPI 16 | app.add_middleware(GZipMiddleware, minimum_size=1000) 17 | 18 | app = FastAPI() 19 | 20 | @app.get("/index") 21 | async def gzip(): 22 | return { 23 | 'code':200 24 | } 25 | 26 | if __name__ == "__main__": 27 | import uvicorn 28 | import os 29 | 30 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 31 | print(app_modeel_name) 32 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 33 | -------------------------------------------------------------------------------- /chapter08/databases_sql/user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/databases_sql/user.db -------------------------------------------------------------------------------- /chapter08/databases_sqlalchemy/user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/databases_sqlalchemy/user.db -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/alembic/versions/287a3cf31b84_shann.py: -------------------------------------------------------------------------------- 1 | """SHANn 2 | 3 | Revision ID: 287a3cf31b84 4 | Revises: 3328ff109aa7 5 | Create Date: 2022-04-04 12:26:15.416620 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '287a3cf31b84' 14 | down_revision = '3328ff109aa7' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.drop_column('users', 'addr') 22 | # ### end Alembic commands ### 23 | 24 | 25 | def downgrade(): 26 | # ### commands auto generated by Alembic - please adjust! ### 27 | op.add_column('users', sa.Column('addr', sa.VARCHAR(length=50), nullable=True)) 28 | # ### end Alembic commands ### 29 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/alembic/versions/3328ff109aa7_add_mobile.py: -------------------------------------------------------------------------------- 1 | """add mobile 2 | 3 | Revision ID: 3328ff109aa7 4 | Revises: 5 | Create Date: 2022-04-04 12:24:42.862656 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '3328ff109aa7' 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.add_column('users', sa.Column('addr', sa.String(length=50), nullable=True)) 22 | # ### end Alembic commands ### 23 | 24 | 25 | def downgrade(): 26 | # ### commands auto generated by Alembic - please adjust! ### 27 | op.drop_column('users', 'addr') 28 | # ### end Alembic commands ### 29 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/api/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 19:59 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/config/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:05 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/db/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:00 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/db/database.py: -------------------------------------------------------------------------------- 1 | # 导入异步引擎的模块 2 | from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession 3 | from sqlalchemy.orm import declarative_base, sessionmaker 4 | # URL地址格式 5 | from config.confiig import get_settings 6 | # 创建异步引擎对象 7 | async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) 8 | # 创建ORM模型基类 9 | Base = declarative_base() 10 | # 创建异步的会话管理对象 11 | SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:00 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | from .user import * -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/models/user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | 4 | from db.database import Base 5 | from sqlalchemy import Column, Integer, String 6 | 7 | class User(Base): 8 | # 指定本类映射到users表 9 | __tablename__ = 'users' 10 | id = Column(Integer, primary_key=True, autoincrement=True) 11 | name = Column(String(20)) 12 | nikename = Column(String(32)) 13 | password = Column(String(32)) 14 | email = Column(String(50)) 15 | # 新增手机号码字段 16 | mobile = Column(String(50)) 17 | # 新增手机号码字段 18 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 22:32 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/servies/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:00 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter08/fastapi_sqlalchemy/user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/fastapi_sqlalchemy/user.db -------------------------------------------------------------------------------- /chapter08/lua_register_script/mian.py: -------------------------------------------------------------------------------- 1 | import time 2 | from uuid import uuid4 3 | 4 | from redis import Redis 5 | 6 | # 创建连接客户端对象 7 | redis = Redis(host="localhost",port=6379) 8 | # 封装获取锁的值和删除锁操作的Lua脚本script内容 9 | script = """ 10 | if redis.call('GET', KEYS[1]) == ARGV[1] then 11 | return redis.call('DEL', KEYS[1]) 12 | else 13 | return 0 14 | end 15 | """ 16 | 17 | 18 | def action(lock_name='pay_order',client_signature=str(uuid4())): 19 | if redis.set(name=lock_name, value=client_signature, nx=True, ex=25): # 锁不存在才能上锁成功,过期时间应为业务时间的五倍,此处故意写小,模拟过期释放 20 | try: 21 | print('处理业务', client_signature) 22 | time.sleep(10) 23 | except Exception as e: 24 | print(e) 25 | finally: 26 | # 释放锁 27 | cmd = redis.register_script(script) 28 | res = cmd(keys=[lock_name], args=[client_signature]) # 执行脚本 29 | if res: 30 | print('锁已释放') 31 | else: 32 | print('不是自己的锁') 33 | else: 34 | print('锁已存在') 35 | 36 | 37 | if __name__ == '__main__': 38 | action() 39 | -------------------------------------------------------------------------------- /chapter08/sql_model/main.py: -------------------------------------------------------------------------------- 1 | from sqlmodel import create_engine 2 | ASYNC_DATABASE_URI = "sqlite+aiosqlite:///aiosqlite_user.db" 3 | engine = create_engine(ASYNC_DATABASE_URI) -------------------------------------------------------------------------------- /chapter08/sqlalchemy_async_sqlite3/aiosqlite_user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/sqlalchemy_async_sqlite3/aiosqlite_user.db -------------------------------------------------------------------------------- /chapter08/sqlalchemy_sync_sqlite3/user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/sqlalchemy_sync_sqlite3/user.db -------------------------------------------------------------------------------- /chapter08/sqlite3_connect/main.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | connection = sqlite3.connect('test.db') 4 | # 创建游标 5 | cursor = connection.cursor() 6 | # 创建表 7 | cursor.execute('''CREATE TABLE user 8 | (id INT PRIMARY KEY NOT NULL, 9 | username TEXT NOT NULL, 10 | password TEXT NOT NULL);''') 11 | # 数据保存 12 | cursor.execute("INSERT INTO user (id,username,password) VALUES (1, 'xiaozhong', '123456')") 13 | cursor.execute("INSERT INTO user (id,username,password) VALUES (2, 'muyu', '123456')") 14 | # 数据查询 15 | cursor = cursor.execute("SELECT id, username, password from user") 16 | for row in cursor: 17 | print(row) 18 | connection.commit() 19 | # 数据更新 20 | cursor.execute("UPDATE user set username ='xiaoxiao' where id = 1") 21 | connection.commit() 22 | # 数据删除 23 | cursor.execute("DELETE from user where id=1;") 24 | connection.commit() 25 | # 关闭数据库连接 26 | connection.close() 27 | -------------------------------------------------------------------------------- /chapter08/sqlite3_connect/test.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/sqlite3_connect/test.db -------------------------------------------------------------------------------- /chapter08/sqlmodel_async_sqlite3/aiosqlite_user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/sqlmodel_async_sqlite3/aiosqlite_user.db -------------------------------------------------------------------------------- /chapter08/sqlmodel_sync_sqlite3/user.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter08/sqlmodel_sync_sqlite3/user.db -------------------------------------------------------------------------------- /chapter09/jwt_use/main.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | from jose import jwt 3 | from datetime import datetime 4 | 5 | 6 | SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" 7 | ALGORITHM = "HS256" 8 | ACCESS_TOKEN_EXPIRE_MINUTES = 30 9 | REFRRSH_ACCESS_TOKEN_EXPIRE_MINUTES = 70 10 | 11 | 12 | class TokenUtils: 13 | 14 | @staticmethod 15 | def token_encode(data): 16 | jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM) 17 | return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM) 18 | 19 | @staticmethod 20 | def token_decode(token): 21 | return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) 22 | 23 | 24 | data = { 25 | 'iss ': "xiaozhong", 26 | 'sub': 'xiaozhongtongxue', 27 | 'name': 'superadmin', 28 | 'admin': True, 29 | 'exp': datetime.utcnow() + timedelta(minutes=15) 30 | } 31 | 32 | 33 | token = TokenUtils.token_encode(data=data) 34 | print(token) 35 | payload = TokenUtils.token_decode(token =token) 36 | print(payload) 37 | -------------------------------------------------------------------------------- /chapter09/mode_code/get_token.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | # 定义我们的APP服务对象 4 | app = FastAPI() 5 | 6 | 7 | @app.get("/get/access_token") 8 | async def access_token(code: str): 9 | import requests 10 | # 第三方服务端请求授权服务器获取access_token的地址 11 | rsp = requests.get(f"http://127.0.0.1:8000/oauth2/authorize/access_token?client_id=xiaozhong&client_secret=123456&code={code}").json() 12 | access_token = rsp.get('access_token') 13 | refresh_token = rsp.get('refresh_token') 14 | access_token_expires = rsp.get('expires_in') 15 | username = rsp.get('userid') 16 | return { 17 | "access_token": access_token, 18 | # access_token接口调用凭证超时时间 19 | "expires_in": access_token_expires, 20 | "refresh_token": refresh_token, 21 | "token_type": "bearer", 22 | "userid": username, 23 | "scope": "SCOPE" 24 | } 25 | 26 | 27 | if __name__ == '__main__': 28 | import uvicorn 29 | uvicorn.run('get_token:app', host="127.0.0.1", port=8100, debug=True, reload=True) -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/api/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 19:59 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/api/short.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends,BackgroundTasks 2 | from fastapi.responses import RedirectResponse, PlainTextResponse 3 | from dependencies import get_db_session 4 | from db.database import AsyncSession 5 | from servies.short import ShortServeries 6 | 7 | router_short = APIRouter(tags=["短链访问"]) 8 | 9 | 10 | @router_short.get('/{short_tag}') 11 | async def short_redirect(*,short_tag: str, db_session: AsyncSession = Depends(get_db_session),taks:BackgroundTasks): 12 | data = await ShortServeries.get_short_url(db_session, short_tag) 13 | if not data: 14 | return PlainTextResponse("没有对应短链信息记录") 15 | data.visits_count=data.visits_count+1 16 | taks.add_task(ShortServeries.update_short_url,db_session,short_url_id=data.id,visits_count=data.visits_count) 17 | return RedirectResponse(url=data.long_url) -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/config/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:05 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/db/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:00 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/db/database.py: -------------------------------------------------------------------------------- 1 | # 导入异步引擎的模块 2 | from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession 3 | from sqlalchemy.orm import declarative_base, sessionmaker 4 | # URL地址格式 5 | from config.config import get_settings 6 | # 创建异步引擎对象 7 | async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) 8 | # 创建ORM模型基类 9 | Base = declarative_base() 10 | # 创建异步的会话管理对象 11 | SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) 12 | -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:00 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | 35 | 36 | from .model import User -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/models/model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | 4 | from db.database import Base 5 | from sqlalchemy import Column, Integer, String, DateTime, func 6 | 7 | 8 | class User(Base): 9 | # 指定本类映射到users表 10 | __tablename__ = 'user' 11 | id = Column(Integer, primary_key=True, autoincrement=True) 12 | # 用户姓名 13 | username = Column(String(20)) 14 | # 用户密码 15 | password = Column(String(32)) 16 | # 用户创建时间 17 | created_at = Column(DateTime(), default=func.now()) 18 | 19 | class ShortUrl(Base): 20 | # 指定本类映射到users表 21 | __tablename__ = 'short_url' 22 | id = Column(Integer, primary_key=True, autoincrement=True) 23 | # 短链标签 24 | short_tag = Column(String(20),nullable=False) 25 | # 短连接地址 26 | short_url = Column(String(20)) 27 | # 长链接地址 28 | long_url = Column(String, nullable=False) 29 | # 访问次数 30 | visits_count= Column(Integer, nullable=True) 31 | # 短链创建时间 32 | created_at = Column(DateTime(), default=func.now()) 33 | # 短链创建时间 34 | created_by = Column(String(20)) 35 | # 短信内容 36 | msg_context = Column(String, nullable=False) -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 22:32 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/servies/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # coding=utf-8 3 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + + 4 | # ┏┓   ┏┓+ + 5 | #    ┏┛┻━━━┛┻┓ + + 6 | #    ┃       ┃   7 | #    ┃   ━   ┃ ++ + + + 8 | #    ████━████ ┃+ 9 | #    ┃       ┃ + 10 | #    ┃   ┻   ┃ 11 | #    ┃       ┃ + + 12 | #    ┗━┓   ┏━┛ 13 | #      ┃   ┃            14 | #      ┃   ┃ + + + + 15 | #      ┃   ┃    Codes are far away from bugs with the animal protecting    16 | #      ┃   ┃ +     神兽保佑,代码无bug   17 | #      ┃   ┃ 18 | #      ┃   ┃  +          19 | #      ┃    ┗━━━┓ + + 20 | #      ┃        ┣┓ 21 | #      ┃        ┏┛ 22 | #      ┗┓┓┏━┳┓┏┛ + + + + 23 | #       ┃┫┫ ┃┫┫ 24 | #       ┗┻┛ ┗┻┛+ + + + 25 | # + + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + ++ + + +""" 26 | """ 27 | Author = zyx 28 | @Create_Time: 2022/4/3 20:00 29 | @version: v1.0.0 30 | @Contact: 308711822@qq.com 31 | @File: __init__.py.py 32 | @文件功能描述:------ 33 | """ 34 | -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/short.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/shorr_url_pro/short.db -------------------------------------------------------------------------------- /chapter10/shorr_url_pro/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/shorr_url_pro/utils/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/api/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/api/short.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends,BackgroundTasks 2 | from fastapi.responses import RedirectResponse, PlainTextResponse 3 | 4 | from dependencies import get_db_session 5 | from db.database import AsyncSession 6 | from servies.short import ShortServeries 7 | 8 | router_short = APIRouter(tags=["短链访问"]) 9 | 10 | 11 | @router_short.get('/{short_tag}') 12 | async def short_redirect(*,short_tag: str, db_session: AsyncSession = Depends(get_db_session),taks:BackgroundTasks): 13 | data = await ShortServeries.get_short_url(db_session, short_tag) 14 | if not data: 15 | return PlainTextResponse("没有对应短链信息记录") 16 | data.visits_count=data.visits_count+1 17 | taks.add_task(ShortServeries.update_short_url,db_session,short_url_id=data.id,visits_count=data.visits_count) 18 | return RedirectResponse(url=data.long_url) 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter10/short_url_pro/app.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from api.short import router_short 3 | from api.user import router_uesr 4 | app = FastAPI(title='fastapi集成短链实战案例') 5 | 6 | @app.on_event("startup") 7 | async def startup_event(): 8 | pass 9 | from db.database import async_engine, Base 10 | from models.model import User,ShortUrl 11 | async def init_create_table(): 12 | async with async_engine.begin() as conn: 13 | # await conn.run_sync(Base.metadata.drop_all) 14 | await conn.run_sync(Base.metadata.create_all) 15 | await init_create_table() 16 | 17 | @app.on_event("shutdown") 18 | async def shutdown_event(): 19 | pass 20 | 21 | from api.short import router_short 22 | from api.user import router_uesr 23 | app.include_router(router_short) 24 | app.include_router(router_uesr) 25 | 26 | print('启动!') 27 | if __name__ == '__main__': 28 | import uvicorn 29 | uvicorn.run(app='app:app', host="127.0.0.1", port=8000, reload=True) -------------------------------------------------------------------------------- /chapter10/short_url_pro/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/config/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/config/config.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseSettings 2 | from functools import lru_cache 3 | 4 | class Settings(BaseSettings): 5 | # 定义连接异步引擎数据库的URL地址 6 | ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///short.db" 7 | # 定义TOEKN的签名信息值 8 | TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' 9 | 10 | @lru_cache() 11 | def get_settings(): 12 | return Settings() 13 | -------------------------------------------------------------------------------- /chapter10/short_url_pro/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/db/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/db/database.py: -------------------------------------------------------------------------------- 1 | # 导入异步引擎的模块 2 | from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession 3 | from sqlalchemy.orm import declarative_base, sessionmaker 4 | # URL地址格式 5 | from config.config import get_settings 6 | # 创建异步引擎对象 7 | async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) 8 | # 创建ORM模型基类 9 | Base = declarative_base() 10 | # 创建异步的会话管理对象 11 | SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) -------------------------------------------------------------------------------- /chapter10/short_url_pro/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.exc import SQLAlchemyError 2 | from sqlalchemy.ext.asyncio import AsyncSession 3 | from typing import AsyncGenerator 4 | from db.database import SessionLocal 5 | 6 | async def get_db_session() -> AsyncGenerator[AsyncSession, None]: 7 | db_session = None 8 | try: 9 | db_session = SessionLocal() 10 | yield db_session 11 | finally: 12 | await db_session.close() 13 | 14 | from contextlib import asynccontextmanager 15 | @asynccontextmanager 16 | async def get_db_session_asynccont() -> AsyncGenerator: 17 | async_session = SessionLocal() 18 | try: 19 | yield async_session 20 | await async_session.commit() 21 | except SQLAlchemyError as ex: 22 | await async_session.rollback() 23 | raise ex 24 | finally: 25 | await async_session.close() -------------------------------------------------------------------------------- /chapter10/short_url_pro/main.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | if __name__ == '__main__': 3 | import uvicorn 4 | 5 | uvicorn.run(app='main:app', host="127.0.0.1", port=8000) -------------------------------------------------------------------------------- /chapter10/short_url_pro/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/models/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/models/model.py: -------------------------------------------------------------------------------- 1 | from db.database import Base 2 | from sqlalchemy import Column, String, DateTime, func,Integer#Integer 3 | 4 | class User(Base): 5 | # 指定本类映射到users表 6 | __tablename__ = 'user' 7 | id = Column(Integer, primary_key=True, autoincrement=True) 8 | # 用户姓名 9 | username = Column(String(20)) 10 | # 用户密码 11 | password = Column(String(32)) 12 | # 用户创建时间 13 | created_at = Column(DateTime(), default=func.now()) 14 | 15 | class ShortUrl(Base): 16 | # 指定本类映射到users表 17 | __tablename__ = 'short_url' 18 | id = Column(Integer, primary_key=True, autoincrement=True) 19 | # 短链标签 20 | short_tag = Column(String(20),nullable=False) 21 | # 短连接地址 22 | short_url = Column(String(20)) 23 | # 长链接地址 24 | long_url = Column(String, nullable=False) 25 | # 访问次数 26 | visits_count= Column(Integer, nullable=True) 27 | # 短链创建时间 28 | created_at = Column(DateTime(), default=func.now()) 29 | # 短链创建时间 30 | created_by = Column(String(20)) 31 | # 短信内容 32 | msg_context = Column(String, nullable=False) -------------------------------------------------------------------------------- /chapter10/short_url_pro/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | class SingleShortUrlCreate(BaseModel): 4 | """ 5 | 创建新短链记录时候需要传递参数信息 6 | """ 7 | # 需要生成长链接地址 8 | long_url:str 9 | # 群发短信内容 10 | msg_context:str 11 | # 短连接生成前缀 12 | short_url:str = "http://127.0.0.1:8000/" 13 | # 访问次数-默认值是0 14 | visits_count:int = 0 15 | # 短链标签-默认可以不传 16 | short_tag:str = "" 17 | # 默认不传-通常后端进行生成处理 18 | created_by = "" 19 | 20 | -------------------------------------------------------------------------------- /chapter10/short_url_pro/servies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/servies/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/servies/short.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/servies/short.db -------------------------------------------------------------------------------- /chapter10/short_url_pro/short.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/short.db -------------------------------------------------------------------------------- /chapter10/short_url_pro/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter10/short_url_pro/utils/__init__.py -------------------------------------------------------------------------------- /chapter10/short_url_pro/utils/passlib_hepler.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | 6 | class PasslibHelper: 7 | pass 8 | 9 | # plain_password 明文密码,hashed_password哈希密码 10 | @staticmethod 11 | def verity_password(plain_password: str, hashed_password: str): 12 | """对密码进行校验""" 13 | return pwd_context.verify(plain_password, hashed_password) 14 | 15 | # 进行哈希 密码加密 16 | @staticmethod 17 | def hash_password(password: str) -> str: 18 | return pwd_context.hash(password) 19 | 20 | if __name__ == '__main__': 21 | print(PasslibHelper.hash_password("123456")) -------------------------------------------------------------------------------- /chapter10/short_url_pro/utils/random_helper.py: -------------------------------------------------------------------------------- 1 | import string 2 | import random 3 | 4 | 5 | 6 | def generate_short_url(size=7) -> str: 7 | letters = string.ascii_letters + string.digits 8 | short_tag = ''.join(random.choice(letters) for i in range(size)) 9 | return short_tag -------------------------------------------------------------------------------- /chapter11/distributed_websocket/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/api/__init__.py -------------------------------------------------------------------------------- /chapter11/distributed_websocket/chat.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/chat.db -------------------------------------------------------------------------------- /chapter11/distributed_websocket/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/config/__init__.py -------------------------------------------------------------------------------- /chapter11/distributed_websocket/config/config.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseSettings 2 | from functools import lru_cache 3 | 4 | class Settings(BaseSettings): 5 | # 定义连接异步引擎数据库的URL地址 6 | ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///chat.db" 7 | # 定义TOEKN的签名信息值 8 | TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' 9 | 10 | @lru_cache() 11 | def get_settings(): 12 | return Settings() 13 | -------------------------------------------------------------------------------- /chapter11/distributed_websocket/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/db/__init__.py -------------------------------------------------------------------------------- /chapter11/distributed_websocket/db/database.py: -------------------------------------------------------------------------------- 1 | # 导入异步引擎的模块 2 | from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession 3 | from sqlalchemy.orm import declarative_base, sessionmaker 4 | # URL地址格式 5 | from config.config import get_settings 6 | # 创建异步引擎对象 7 | async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) 8 | # 创建ORM模型基类 9 | Base = declarative_base() 10 | # 创建异步的会话管理对象 11 | SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) -------------------------------------------------------------------------------- /chapter11/distributed_websocket/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.asyncio import AsyncSession 2 | from typing import AsyncGenerator 3 | from db.database import SessionLocal 4 | 5 | async def get_db_session() -> AsyncGenerator[AsyncSession, None]: 6 | db_session = None 7 | try: 8 | db_session = SessionLocal() 9 | yield db_session 10 | finally: 11 | await db_session.close() -------------------------------------------------------------------------------- /chapter11/distributed_websocket/main.py: -------------------------------------------------------------------------------- 1 | 2 | from app import creat_app 3 | app =creat_app() 4 | if __name__ == '__main__': 5 | import uvicorn 6 | uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True) 7 | -------------------------------------------------------------------------------- /chapter11/distributed_websocket/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/models/__init__.py -------------------------------------------------------------------------------- /chapter11/distributed_websocket/models/model.py: -------------------------------------------------------------------------------- 1 | from db.database import Base 2 | from sqlalchemy import Column, String, DateTime, func,Integer#Integer 3 | 4 | class User(Base): 5 | # 指定本类映射到users表 6 | __tablename__ = 'user' 7 | id = Column(Integer, primary_key=True, autoincrement=True) 8 | # 用户号码 9 | phone_number = Column(String(20)) 10 | # 用户姓名 11 | username = Column(String(20)) 12 | # 用户密码 13 | password = Column(String(32)) 14 | # 用户创建时间 15 | created_at = Column(DateTime(), default=func.now()) 16 | 17 | 18 | -------------------------------------------------------------------------------- /chapter11/distributed_websocket/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from pydantic import BaseModel 3 | from starlette.websockets import WebSocket 4 | 5 | @dataclass 6 | class User: 7 | phone_number: str 8 | username: str 9 | websocket:WebSocket 10 | 11 | 12 | class RegisterAaction(BaseModel): 13 | phone_number: str 14 | username: str 15 | password: str 16 | 17 | class LoginAaction(BaseModel): 18 | phone_number: str 19 | password: str 20 | 21 | 22 | 23 | @dataclass 24 | class UserDistribute : 25 | phone_number: str 26 | username: str 27 | 28 | @dataclass 29 | class WebSocketDistribute : 30 | websocket:WebSocket 31 | -------------------------------------------------------------------------------- /chapter11/distributed_websocket/servies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/servies/__init__.py -------------------------------------------------------------------------------- /chapter11/distributed_websocket/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/distributed_websocket/utils/__init__.py -------------------------------------------------------------------------------- /chapter11/distributed_websocket/utils/auth_helper.py: -------------------------------------------------------------------------------- 1 | 2 | from fastapi import HTTPException,status 3 | from jose import JWTError, jwt 4 | from pydantic import BaseModel, ValidationError 5 | from jose import jwt 6 | 7 | SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" 8 | ALGORITHM = "HS256" 9 | 10 | 11 | 12 | class AuthToeknHelper: 13 | 14 | @staticmethod 15 | def token_encode(data): 16 | jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM) 17 | return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM) 18 | 19 | @staticmethod 20 | def token_decode(token): 21 | credentials_exception = HTTPException( 22 | status_code=status.HTTP_401_UNAUTHORIZED, 23 | detail="Could not validate credentials", 24 | headers={"WWW-Authenticate": f"Bearer"}, 25 | ) 26 | try: 27 | # 开始反向解析我们的TOKEN.,解析相关的信息 28 | payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) 29 | except (JWTError, ValidationError): 30 | raise credentials_exception 31 | return payload 32 | -------------------------------------------------------------------------------- /chapter11/distributed_websocket/utils/passlib_hepler.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | 6 | class PasslibHelper: 7 | pass 8 | 9 | # plain_password 明文密码,hashed_password哈希密码 10 | @staticmethod 11 | def verity_password(plain_password: str, hashed_password: str): 12 | """对密码进行校验""" 13 | return pwd_context.verify(plain_password, hashed_password) 14 | 15 | # 进行哈希 密码加密 16 | @staticmethod 17 | def hash_password(password: str) -> str: 18 | return pwd_context.hash(password) 19 | 20 | if __name__ == '__main__': 21 | print(PasslibHelper.hash_password("123456")) -------------------------------------------------------------------------------- /chapter11/distributed_websocket/utils/random_helper.py: -------------------------------------------------------------------------------- 1 | import string 2 | import random 3 | 4 | 5 | 6 | def generate_short_url(size=7) -> str: 7 | letters = string.ascii_letters + string.digits 8 | short_tag = ''.join(random.choice(letters) for i in range(size)) 9 | return short_tag -------------------------------------------------------------------------------- /chapter11/websocket/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/api/__init__.py -------------------------------------------------------------------------------- /chapter11/websocket/app.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List, Optional 2 | from fastapi import Body, FastAPI, HTTPException 3 | from api import room 4 | from api import user 5 | 6 | 7 | app = FastAPI() 8 | 9 | 10 | @app.on_event("startup") 11 | async def startup_event(): 12 | pass 13 | from db.database import async_engine, Base 14 | from models.model import User 15 | async def init_create_table(): 16 | async with async_engine.begin() as conn: 17 | # await conn.run_sync(Base.metadata.drop_all) 18 | await conn.run_sync(Base.metadata.create_all) 19 | 20 | await init_create_table() 21 | # 实例化房间连接管理类 22 | 23 | 24 | @app.on_event("shutdown") 25 | async def shutdown_event(): 26 | pass 27 | 28 | 29 | # 注册路由 30 | 31 | app.include_router(user.router_uesr) 32 | app.include_router(room.router_char) 33 | 34 | 35 | def creat_app(): 36 | return app 37 | -------------------------------------------------------------------------------- /chapter11/websocket/chat.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/chat.db -------------------------------------------------------------------------------- /chapter11/websocket/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/config/__init__.py -------------------------------------------------------------------------------- /chapter11/websocket/config/config.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseSettings 2 | from functools import lru_cache 3 | 4 | class Settings(BaseSettings): 5 | # 定义连接异步引擎数据库的URL地址 6 | ASYNC_DATABASE_URI: str = "sqlite+aiosqlite:///chat.db" 7 | # 定义TOEKN的签名信息值 8 | TOKEN_SIGN_SECRET:str = 'ZcjT6Rcp1yIFQoS7' 9 | 10 | @lru_cache() 11 | def get_settings(): 12 | return Settings() 13 | -------------------------------------------------------------------------------- /chapter11/websocket/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/db/__init__.py -------------------------------------------------------------------------------- /chapter11/websocket/db/database.py: -------------------------------------------------------------------------------- 1 | # 导入异步引擎的模块 2 | from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession 3 | from sqlalchemy.orm import declarative_base, sessionmaker 4 | # URL地址格式 5 | from config.config import get_settings 6 | # 创建异步引擎对象 7 | async_engine = create_async_engine(get_settings().ASYNC_DATABASE_URI, echo=False) 8 | # 创建ORM模型基类 9 | Base = declarative_base() 10 | # 创建异步的会话管理对象 11 | SessionLocal = sessionmaker(bind=async_engine, expire_on_commit=False, class_=AsyncSession) -------------------------------------------------------------------------------- /chapter11/websocket/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.asyncio import AsyncSession 2 | from typing import AsyncGenerator 3 | from db.database import SessionLocal 4 | 5 | async def get_db_session() -> AsyncGenerator[AsyncSession, None]: 6 | db_session = None 7 | try: 8 | db_session = SessionLocal() 9 | yield db_session 10 | finally: 11 | await db_session.close() -------------------------------------------------------------------------------- /chapter11/websocket/main.py: -------------------------------------------------------------------------------- 1 | 2 | from app import creat_app 3 | app =creat_app() 4 | if __name__ == '__main__': 5 | import uvicorn 6 | uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True) 7 | -------------------------------------------------------------------------------- /chapter11/websocket/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/models/__init__.py -------------------------------------------------------------------------------- /chapter11/websocket/models/model.py: -------------------------------------------------------------------------------- 1 | from db.database import Base 2 | from sqlalchemy import Column, String, DateTime, func,Integer#Integer 3 | 4 | class User(Base): 5 | # 指定本类映射到users表 6 | __tablename__ = 'user' 7 | id = Column(Integer, primary_key=True, autoincrement=True) 8 | # 用户号码 9 | phone_number = Column(String(20)) 10 | # 用户姓名 11 | username = Column(String(20)) 12 | # 用户密码 13 | password = Column(String(32)) 14 | # 用户创建时间 15 | created_at = Column(DateTime(), default=func.now()) 16 | 17 | 18 | -------------------------------------------------------------------------------- /chapter11/websocket/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from pydantic import BaseModel 3 | from starlette.websockets import WebSocket 4 | 5 | @dataclass 6 | class User: 7 | phone_number: str 8 | username: str 9 | websocket:WebSocket 10 | 11 | 12 | class RegisterAaction(BaseModel): 13 | phone_number: str 14 | username: str 15 | password: str 16 | 17 | class LoginAaction(BaseModel): 18 | phone_number: str 19 | password: str 20 | 21 | 22 | 23 | @dataclass 24 | class UserDistribute : 25 | phone_number: str 26 | username: str 27 | 28 | @dataclass 29 | class WebSocketDistribute : 30 | websocket:WebSocket 31 | -------------------------------------------------------------------------------- /chapter11/websocket/servies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/servies/__init__.py -------------------------------------------------------------------------------- /chapter11/websocket/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter11/websocket/utils/__init__.py -------------------------------------------------------------------------------- /chapter11/websocket/utils/auth_helper.py: -------------------------------------------------------------------------------- 1 | 2 | from fastapi import HTTPException,status 3 | from jose import JWTError, jwt 4 | from pydantic import BaseModel, ValidationError 5 | from jose import jwt 6 | 7 | SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" 8 | ALGORITHM = "HS256" 9 | 10 | 11 | 12 | class AuthToeknHelper: 13 | 14 | @staticmethod 15 | def token_encode(data): 16 | jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM) 17 | return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM) 18 | 19 | @staticmethod 20 | def token_decode(token): 21 | credentials_exception = HTTPException( 22 | status_code=status.HTTP_401_UNAUTHORIZED, 23 | detail="Could not validate credentials", 24 | headers={"WWW-Authenticate": f"Bearer"}, 25 | ) 26 | try: 27 | # 开始反向解析我们的TOKEN.,解析相关的信息 28 | payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) 29 | except (JWTError, ValidationError): 30 | raise credentials_exception 31 | return payload 32 | -------------------------------------------------------------------------------- /chapter11/websocket/utils/passlib_hepler.py: -------------------------------------------------------------------------------- 1 | from passlib.context import CryptContext 2 | 3 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 4 | 5 | 6 | class PasslibHelper: 7 | pass 8 | 9 | # plain_password 明文密码,hashed_password哈希密码 10 | @staticmethod 11 | def verity_password(plain_password: str, hashed_password: str): 12 | """对密码进行校验""" 13 | return pwd_context.verify(plain_password, hashed_password) 14 | 15 | # 进行哈希 密码加密 16 | @staticmethod 17 | def hash_password(password: str) -> str: 18 | return pwd_context.hash(password) 19 | 20 | if __name__ == '__main__': 21 | print(PasslibHelper.hash_password("123456")) -------------------------------------------------------------------------------- /chapter11/websocket/utils/random_helper.py: -------------------------------------------------------------------------------- 1 | import string 2 | import random 3 | 4 | 5 | 6 | def generate_short_url(size=7) -> str: 7 | letters = string.ascii_letters + string.digits 8 | short_tag = ''.join(random.choice(letters) for i in range(size)) 9 | return short_tag -------------------------------------------------------------------------------- /chapter12/booking_system/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/apis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/apis/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/apis/doctor/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_docrot = APIRouter(prefix='/api/v1',tags=["医生信息模块"],include_in_schema=True) 3 | from ..api import doctor_api -------------------------------------------------------------------------------- /chapter12/booking_system/apis/doctor/dependencies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/apis/doctor/dependencies/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/apis/doctor/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SchedulingInfo(BaseModel): 5 | # 预约医生编号 6 | dno: str 7 | # 预约时间 8 | start_time: str = None 9 | 10 | 11 | class MakeReserveOrderForm(BaseModel): 12 | # 预约医生编号 13 | dno: str 14 | # 预约医生排号时段 15 | nsindex: str 16 | 17 | 18 | class PayReserveOrderForm(BaseModel): 19 | # 预约医生编号 20 | dno: str 21 | # 预约医生排号时段 22 | nsindex: str 23 | # 预约人信息 24 | visit_uname: str 25 | visit_uphone: str 26 | visit_uopenid: str = None 27 | visit_usex: str 28 | visit_uage: str 29 | -------------------------------------------------------------------------------- /chapter12/booking_system/apis/hospital/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/apis/hospital/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/apis/hospital/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_hospital = APIRouter(prefix='/api/v1',tags=["医院信息模块"]) 3 | # 導入模塊 4 | from apis.hospital.api import get_hospital_info -------------------------------------------------------------------------------- /chapter12/booking_system/apis/hospital/api/get_hospital_info.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from apis.hospital.repository import HospitalServeries 3 | from db.async_database import depends_get_db_session 4 | from db.async_database import AsyncSession 5 | from exts.responses.json_response import Success 6 | from ..api import router_hospital 7 | 8 | 9 | @router_hospital.get("/hospital_info", summary='获取医院信息') 10 | async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): 11 | info = await HospitalServeries.get_hospital_info(db_session, id=1) 12 | return Success(result=info) 13 | -------------------------------------------------------------------------------- /chapter12/booking_system/apis/hospital/repository/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import select, update, delete 2 | from sqlalchemy.ext.asyncio import AsyncSession 3 | from db.models import Hospitalinfo 4 | from db.async_database import async_engine, Base 5 | 6 | 7 | class HospitalServeries: 8 | 9 | @staticmethod 10 | async def get_hospital_info(async_session: AsyncSession, id: int): 11 | _result = await async_session.execute( 12 | select(Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages).where(Hospitalinfo.id == id)) 13 | scalars_result = _result.first() 14 | # scalars_result = _result.scalars().first() 15 | return scalars_result 16 | -------------------------------------------------------------------------------- /chapter12/booking_system/apis/payorders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/apis/payorders/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/apis/payorders/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_payorders = APIRouter(prefix='/api/v1',tags=["支付订单模块"]) 3 | from apis.payorders.api import doctor_reserve_order 4 | from apis.payorders.api import payback_reserve_order 5 | from apis.payorders.api import reserve_order_info 6 | from apis.payorders.api import doctor_reserve_reorder 7 | from apis.payorders.api import doctor_order_check -------------------------------------------------------------------------------- /chapter12/booking_system/apis/payorders/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | from starlette.requests import Request 2 | 3 | def get_client_ip(request: Request): 4 | """ 5 | 获取客户端真实ip 6 | :param request: 7 | :return: 8 | """ 9 | forwarded = request.headers.get("X-Forwarded-For") 10 | if forwarded: 11 | return forwarded.split(",")[0] 12 | return request.client.host -------------------------------------------------------------------------------- /chapter12/booking_system/apis/userorders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/apis/userorders/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/apis/userorders/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_userorders = APIRouter(prefix='/api/v1', tags=["用户订单模块"]) 3 | from apis.userorders.api import refund_reserve_order, unpay_reserve_order, user_order_info, user_order_list, \ 4 | wxauth_login 5 | -------------------------------------------------------------------------------- /chapter12/booking_system/apis/userorders/api/user_order_list.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from db.async_database import depends_get_db_session 3 | from db.async_database import AsyncSession 4 | from exts.responses.json_response import Success, Fail 5 | from ..api import router_userorders 6 | from ..schemas import UserOrderIonfoListForm 7 | from ..repository import Serveries 8 | 9 | @router_userorders.post("/user_order_list", summary='用户自己订单列表') 10 | async def callbadk(forms: UserOrderIonfoListForm, db_session: AsyncSession = Depends(depends_get_db_session)): 11 | # 检测用户的有消息 12 | # 判断当前用户是否已经被拉黑啦,禁用了! 13 | result = await Serveries.get_order_info_list_by_visit_uopenid_select(db_session,visit_uopenid=forms.visit_uopenid,statue=forms.statue) 14 | # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 15 | return Success(api_code=200, result=result, message='查询成功') if result else Fail(api_code=200, result=None, message='无此订单状态列表信息!') 16 | -------------------------------------------------------------------------------- /chapter12/booking_system/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/config/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/db/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/exts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/exts/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/exts/requestvar/bing.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() 24 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/responses/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | ------------------------------------------------- 5 | 文件名称 : __init__.py 6 | 文件功能描述 : 功能描述 7 | 创建人 : 小钟同学 8 | 创建时间 : 2021/9/23 9 | ------------------------------------------------- 10 | 修改描述-2021/9/23: 11 | ------------------------------------------------- 12 | """ 13 | from . import json_response 14 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | import logging 4 | 5 | from exts.wechatpy.client import WeChatClient # NOQA 6 | from exts.wechatpy.component import ComponentOAuth, WeChatComponent # NOQA 7 | from exts.wechatpy.exceptions import WeChatClientException, WeChatException, WeChatOAuthException, WeChatPayException # NOQA 8 | from exts.wechatpy.oauth import WeChatOAuth # NOQA 9 | from exts.wechatpy.parser import parse_message # NOQA 10 | from exts.wechatpy.pay import WeChatPay # NOQA 11 | from exts.wechatpy.replies import create_reply # NOQA 12 | 13 | __version__ = '1.8.2' 14 | __author__ = 'messense' 15 | 16 | # Set default logging handler to avoid "No handler found" warnings. 17 | try: # Python 2.7+ 18 | from logging import NullHandler 19 | except ImportError: 20 | class NullHandler(logging.Handler): 21 | def emit(self, record): 22 | pass 23 | 24 | logging.getLogger(__name__).addHandler(NullHandler()) 25 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/_compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | wechatpy._compat 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | This module makes it easy for wechatpy to run on both Python 2 and 3. 7 | 8 | :copyright: (c) 2014 by messense. 9 | :license: MIT, see LICENSE for more details. 10 | """ 11 | from __future__ import absolute_import, unicode_literals 12 | import sys 13 | import six 14 | import warnings 15 | 16 | warnings.warn("Module `wechatpy._compat` is deprecated, will be removed in 2.0" 17 | "use `wechatpy.utils` instead", 18 | DeprecationWarning, stacklevel=2) 19 | 20 | from exts.wechatpy.utils import get_querystring 21 | from exts.wechatpy.utils import json 22 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/client/api/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class BaseWeChatAPI(object): 6 | """ WeChat API base class """ 7 | 8 | def __init__(self, client=None): 9 | self._client = client 10 | 11 | def _get(self, url, **kwargs): 12 | if getattr(self, 'API_BASE_URL', None): 13 | kwargs['api_base_url'] = self.API_BASE_URL 14 | return self._client.get(url, **kwargs) 15 | 16 | def _post(self, url, **kwargs): 17 | if getattr(self, 'API_BASE_URL', None): 18 | kwargs['api_base_url'] = self.API_BASE_URL 19 | 20 | print("当前URL",url) 21 | return self._client.post(url, **kwargs) 22 | 23 | @property 24 | def access_token(self): 25 | return self._client.access_token 26 | 27 | @property 28 | def session(self): 29 | return self._client.session 30 | 31 | @property 32 | def appid(self): 33 | return self._client.appid 34 | 35 | @property 36 | def secret(self): 37 | return self._client.secret 38 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/client/api/merchant/category.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantCategory(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def get_sub_categories(self, cate_id): 11 | res = self._post( 12 | 'merchant/category/getsub', 13 | data={'cate_id': cate_id}, 14 | result_processor=lambda x: x['cate_list'] 15 | ) 16 | return res 17 | 18 | def get_sku_list(self, cate_id): 19 | res = self._post( 20 | 'merchant/category/getsku', 21 | data={'cate_id': cate_id}, 22 | result_processor=lambda x: x['sku_table'] 23 | ) 24 | return res 25 | 26 | def get_properties(self, cate_id): 27 | res = self._post( 28 | 'merchant/category/getproperty', 29 | data={'cate_id': cate_id}, 30 | result_processor=lambda x: x['properties'] 31 | ) 32 | return res 33 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/client/api/merchant/common.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantCommon(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def upload_image(self, filename, image_data): 11 | res = self._post( 12 | 'merchant/common/upload_img', 13 | params={ 14 | 'filename': filename 15 | }, 16 | data=image_data, 17 | result_processor=lambda x: x['image_url'] 18 | ) 19 | return res 20 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/client/api/merchant/stock.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantStock(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def add(self, product_id, quantity, sku_info=''): 11 | return self._post( 12 | 'merchant/stock/add', 13 | data={ 14 | 'product_id': product_id, 15 | 'quantity': quantity, 16 | 'sku_info': sku_info 17 | } 18 | ) 19 | 20 | def reduce(self, product_id, quantity, sku_info=''): 21 | return self._post( 22 | 'merchant/stock/reduce', 23 | data={ 24 | 'product_id': product_id, 25 | 'quantity': quantity, 26 | 'sku_info': sku_info 27 | } 28 | ) 29 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/crypto/cryptography.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 4 | from cryptography.hazmat.backends import default_backend 5 | 6 | 7 | class WeChatCipher(object): 8 | 9 | def __init__(self, key, iv=None): 10 | iv = iv or key[:16] 11 | backend = default_backend() 12 | self.cipher = Cipher( 13 | algorithms.AES(key), 14 | modes.CBC(iv), 15 | backend=backend 16 | ) 17 | 18 | def encrypt(self, plaintext): 19 | encryptor = self.cipher.encryptor() 20 | return encryptor.update(plaintext) + encryptor.finalize() 21 | 22 | def decrypt(self, ciphertext): 23 | decryptor = self.cipher.decryptor() 24 | return decryptor.update(ciphertext) + decryptor.finalize() 25 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/crypto/pkcs7.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.utils import to_binary, byte2int 4 | 5 | 6 | class PKCS7Encoder(object): 7 | block_size = 32 8 | 9 | @classmethod 10 | def encode(cls, text): 11 | length = len(text) 12 | padding_count = cls.block_size - length % cls.block_size 13 | if padding_count == 0: 14 | padding_count = cls.block_size 15 | padding = to_binary(chr(padding_count)) 16 | return text + padding * padding_count 17 | 18 | @classmethod 19 | def decode(cls, decrypted): 20 | padding = byte2int(decrypted[-1]) 21 | if padding < 1 or padding > 32: 22 | padding = 0 23 | return decrypted[:-padding] 24 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/crypto/pycrypto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from Crypto.Cipher import AES 4 | 5 | 6 | class WeChatCipher(object): 7 | 8 | def __init__(self, key, iv=None): 9 | iv = iv or key[:16] 10 | self.cipher = AES.new(key, AES.MODE_CBC, iv) 11 | 12 | def encrypt(self, plaintext): 13 | return self.cipher.encrypt(plaintext) 14 | 15 | def decrypt(self, ciphertext): 16 | return self.cipher.decrypt(ciphertext) 17 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/enterprise/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.enterprise.client import WeChatClient # NOQA 5 | from exts.wechatpy.enterprise.crypto import WeChatCrypto # NOQA 6 | from exts.wechatpy.enterprise.parser import parse_message # NOQA 7 | from exts.wechatpy.enterprise.replies import create_reply # NOQA 8 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/enterprise/client/api/misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.client.api.base import BaseWeChatAPI 5 | 6 | 7 | class WeChatMisc(BaseWeChatAPI): 8 | 9 | def get_wechat_ips(self): 10 | """ 11 | 获取企业微信服务器的ip段 12 | 13 | https://work.weixin.qq.com/api/doc#90000/90135/90238/%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84ip%E6%AE%B5 14 | 15 | :return: 企业微信回调的IP段 16 | """ 17 | res = self._get('getcallbackip') 18 | return res['ip_list'] 19 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.client.api.base import BaseWeChatAPI 5 | 6 | 7 | class WeChatShakeAround(BaseWeChatAPI): 8 | 9 | def get_shake_info(self, ticket): 10 | """ 11 | 获取摇周边的设备及用户信息 12 | 13 | https://qydev.weixin.qq.com/wiki/index.php?title=获取设备及用户信息 14 | 15 | :param ticket: 摇周边业务的ticket,可在摇到的 URL 中得到,ticket 生效时间为30分钟 16 | :return: 设备及用户信息 17 | """ 18 | res = self._post( 19 | 'shakearound/getshakeinfo', 20 | data={ 21 | 'ticket': ticket 22 | } 23 | ) 24 | return res['data'] 25 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/enterprise/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.exceptions import WeChatException 5 | 6 | 7 | class InvalidCorpIdException(WeChatException): 8 | 9 | def __init__(self, errcode=-40005, errmsg='Invalid corp_id'): 10 | super(InvalidCorpIdException, self).__init__(errcode, errmsg) 11 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/enterprise/parser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | import xmltodict 5 | 6 | from exts.wechatpy.enterprise.events import EVENT_TYPES 7 | from exts.wechatpy.enterprise.messages import MESSAGE_TYPES 8 | from exts.wechatpy.messages import UnknownMessage 9 | from exts.wechatpy.utils import to_text 10 | 11 | 12 | def parse_message(xml): 13 | if not xml: 14 | return 15 | message = xmltodict.parse(to_text(xml))['xml'] 16 | message_type = message['MsgType'].lower() 17 | if message_type == 'event': 18 | event_type = message['Event'].lower() 19 | message_class = EVENT_TYPES.get(event_type, UnknownMessage) 20 | else: 21 | message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) 22 | return message_class(message) 23 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/pay/api/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.pay.api.redpack import WeChatRedpack # NOQA 4 | from exts.wechatpy.pay.api.transfer import WeChatTransfer # NOQA 5 | from exts.wechatpy.pay.api.coupon import WeChatCoupon # NOQA 6 | from exts.wechatpy.pay.api.order import WeChatOrder # NOQA 7 | from exts.wechatpy.pay.api.refund import WeChatRefund # NOQA 8 | from exts.wechatpy.pay.api.tools import WeChatTools # NOQA 9 | from exts.wechatpy.pay.api.jsapi import WeChatJSAPI # NOQA 10 | from exts.wechatpy.pay.api.micropay import WeChatMicroPay # NOQA 11 | from exts.wechatpy.pay.api.withhold import WeChatWithhold # NOQA 12 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/pay/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class BaseWeChatPayAPI(object): 6 | """ WeChat Pay API base class """ 7 | def __init__(self, client=None): 8 | self._client = client 9 | 10 | def _get(self, url, **kwargs): 11 | if getattr(self, 'API_BASE_URL', None): 12 | kwargs['api_base_url'] = self.API_BASE_URL 13 | return self._client.get(url, **kwargs) 14 | 15 | def _post(self, url, **kwargs): 16 | if getattr(self, 'API_BASE_URL', None): 17 | kwargs['api_base_url'] = self.API_BASE_URL 18 | return self._client.post(url, **kwargs) 19 | 20 | @property 21 | def appid(self): 22 | return self._client.appid 23 | 24 | @property 25 | def sub_appid(self): 26 | return self._client.sub_appid 27 | 28 | @property 29 | def mch_id(self): 30 | return self._client.mch_id 31 | 32 | @property 33 | def sub_mch_id(self): 34 | return self._client.sub_mch_id 35 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/session/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class SessionStorage(object): 6 | 7 | def get(self, key, default=None): 8 | raise NotImplementedError() 9 | 10 | def set(self, key, value, ttl=None): 11 | raise NotImplementedError() 12 | 13 | def delete(self, key): 14 | raise NotImplementedError() 15 | 16 | def __getitem__(self, key): 17 | self.get(key) 18 | 19 | def __setitem__(self, key, value): 20 | self.set(key, value) 21 | 22 | def __delitem__(self, key): 23 | self.delete(key) 24 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/session/memorystorage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.session import SessionStorage 4 | 5 | 6 | class MemoryStorage(SessionStorage): 7 | 8 | def __init__(self): 9 | self._data = {} 10 | 11 | def get(self, key, default=None): 12 | return self._data.get(key, default) 13 | 14 | def set(self, key, value, ttl=None): 15 | if value is None: 16 | return 17 | self._data[key] = value 18 | 19 | def delete(self, key): 20 | self._data.pop(key, None) 21 | -------------------------------------------------------------------------------- /chapter12/booking_system/exts/wechatpy/session/shovestorage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.session import SessionStorage 4 | 5 | 6 | class ShoveStorage(SessionStorage): 7 | 8 | def __init__(self, shove, prefix='wechatpy'): 9 | self.shove = shove 10 | self.prefix = prefix 11 | 12 | def key_name(self, key): 13 | return '{0}:{1}'.format(self.prefix, key) 14 | 15 | def get(self, key, default=None): 16 | key = self.key_name(key) 17 | try: 18 | return self.shove[key] 19 | except KeyError: 20 | return default 21 | 22 | def set(self, key, value, ttl=None): 23 | if value is None: 24 | return 25 | 26 | key = self.key_name(key) 27 | self.shove[key] = value 28 | 29 | def delete(self, key): 30 | key = self.key_name(key) 31 | try: 32 | del self.shove[key] 33 | except KeyError: 34 | pass 35 | -------------------------------------------------------------------------------- /chapter12/booking_system/main.py: -------------------------------------------------------------------------------- 1 | from app import creat_app 2 | app =creat_app() 3 | if __name__ == "__main__": 4 | import uvicorn 5 | import os 6 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 7 | print(app_modeel_name) 8 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 9 | 10 | 11 | # tree -I "node_modules|cache|test_*" 12 | # tree -I "__pycache__" -------------------------------------------------------------------------------- /chapter12/booking_system/middlewares/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/middlewares/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/middlewares/loger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/middlewares/loger/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/middlewares/loger/bing.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() 24 | -------------------------------------------------------------------------------- /chapter12/booking_system/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/plugins/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/plugins/base.py: -------------------------------------------------------------------------------- 1 | import fastapi 2 | import pydantic 3 | import typing 4 | import abc 5 | 6 | class PluginBase(abc.ABC): 7 | 8 | def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): 9 | if app is not None: 10 | self.init_app(app) 11 | 12 | @abc.abstractmethod 13 | def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: 14 | raise NotImplementedError('需要实现初始化') 15 | -------------------------------------------------------------------------------- /chapter12/booking_system/requirements.txt: -------------------------------------------------------------------------------- 1 | aio-pika==8.0.3 2 | aiormq==6.3.4 3 | anyio==3.6.1 4 | asgiref==3.5.2 5 | asyncpg==0.26.0 6 | certifi==2022.6.15 7 | charset-normalizer==2.1.0 8 | click==8.1.3 9 | colorama==0.4.5 10 | dnspython==2.2.1 11 | email-validator==1.2.1 12 | fastapi==0.79.0 13 | greenlet==1.1.2 14 | gunicorn==20.1.0 15 | h11==0.13.0 16 | httptools==0.4.0 17 | idna==3.3 18 | itsdangerous==2.1.2 19 | Jinja2==3.1.2 20 | MarkupSafe==2.1.1 21 | multidict==6.0.2 22 | optionaldict==0.1.2 23 | orjson==3.7.8 24 | pamqp==3.2.0 25 | pika==1.3.0 26 | psycopg2==2.9.3 27 | pycryptodome==3.15.0 28 | pydantic==1.9.1 29 | python-dotenv==0.20.0 30 | python-multipart==0.0.5 31 | PyYAML==6.0 32 | requests==2.28.1 33 | six==1.16.0 34 | sniffio==1.2.0 35 | SQLAlchemy==1.4.39 36 | starlette==0.19.1 37 | typing_extensions==4.3.0 38 | ujson==5.4.0 39 | urllib3==1.26.10 40 | uvicorn==0.17.6 41 | watchgod==0.8.2 42 | websockets==10.3 43 | xmltodict==0.13.0 44 | yarl==1.7.2 45 | -------------------------------------------------------------------------------- /chapter12/booking_system/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/utils/__init__.py -------------------------------------------------------------------------------- /chapter12/booking_system/utils/cast_helper.py: -------------------------------------------------------------------------------- 1 | def add(a,b): 2 | return a+b; -------------------------------------------------------------------------------- /chapter12/booking_system/utils/run_with_asyncio.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import asyncio 3 | from functools import wraps 4 | from typing import Any, Awaitable, Callable, TypeVar 5 | T = TypeVar("T") 6 | __all__ = ["run_with_asyncio"] 7 | def run_with_asyncio(f: Callable[..., Awaitable[T]]) -> Callable[..., T]: 8 | @wraps(f) 9 | def wrapper(*args: Any, **kwargs: Any) -> T: 10 | print("pajinlail") 11 | return asyncio.run(f(*args, **kwargs)) 12 | return wrapper -------------------------------------------------------------------------------- /chapter12/booking_system/wxchatsdk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter12/booking_system/wxchatsdk/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/apis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/apis/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/apis/doctor/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_docrot = APIRouter(prefix='/api/v1',tags=["医生信息模块"],include_in_schema=True) 3 | from ..api import doctor_api -------------------------------------------------------------------------------- /chapter13/booking_system/apis/doctor/dependencies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/apis/doctor/dependencies/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/apis/doctor/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SchedulingInfo(BaseModel): 5 | # 预约医生编号 6 | dno: str 7 | # 预约时间 8 | start_time: str = None 9 | 10 | 11 | class MakeReserveOrderForm(BaseModel): 12 | # 预约医生编号 13 | dno: str 14 | # 预约医生排号时段 15 | nsindex: str 16 | 17 | 18 | class PayReserveOrderForm(BaseModel): 19 | # 预约医生编号 20 | dno: str 21 | # 预约医生排号时段 22 | nsindex: str 23 | # 预约人信息 24 | visit_uname: str 25 | visit_uphone: str 26 | visit_uopenid: str = None 27 | visit_usex: str 28 | visit_uage: str 29 | -------------------------------------------------------------------------------- /chapter13/booking_system/apis/hospital/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/apis/hospital/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/apis/hospital/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_hospital = APIRouter(prefix='/api/v1',tags=["医院信息模块"]) 3 | # 導入模塊 4 | from apis.hospital.api import get_hospital_info -------------------------------------------------------------------------------- /chapter13/booking_system/apis/hospital/api/get_hospital_info.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from apis.hospital.repository import HospitalServeries 3 | from db.async_database import depends_get_db_session 4 | from db.async_database import AsyncSession 5 | from exts.responses.json_response import Success 6 | from ..api import router_hospital 7 | 8 | 9 | @router_hospital.get("/hospital_info", summary='获取医院信息') 10 | async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): 11 | info = await HospitalServeries.get_hospital_info(db_session, id=1) 12 | return Success(result=info) 13 | -------------------------------------------------------------------------------- /chapter13/booking_system/apis/hospital/repository/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import select, update, delete 2 | from sqlalchemy.ext.asyncio import AsyncSession 3 | from db.models import Hospitalinfo 4 | from db.async_database import async_engine, Base 5 | 6 | 7 | class HospitalServeries: 8 | 9 | @staticmethod 10 | async def get_hospital_info(async_session: AsyncSession, id: int): 11 | _result = await async_session.execute( 12 | select(Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages).where(Hospitalinfo.id == id)) 13 | scalars_result = _result.first() 14 | # scalars_result = _result.scalars().first() 15 | return scalars_result 16 | -------------------------------------------------------------------------------- /chapter13/booking_system/apis/payorders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/apis/payorders/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/apis/payorders/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_payorders = APIRouter(prefix='/api/v1',tags=["支付订单模块"]) 3 | from apis.payorders.api import doctor_reserve_order 4 | from apis.payorders.api import payback_reserve_order 5 | from apis.payorders.api import reserve_order_info 6 | from apis.payorders.api import doctor_reserve_reorder 7 | from apis.payorders.api import doctor_order_check -------------------------------------------------------------------------------- /chapter13/booking_system/apis/payorders/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | from starlette.requests import Request 2 | 3 | def get_client_ip(request: Request): 4 | """ 5 | 获取客户端真实ip 6 | :param request: 7 | :return: 8 | """ 9 | forwarded = request.headers.get("X-Forwarded-For") 10 | if forwarded: 11 | return forwarded.split(",")[0] 12 | return request.client.host -------------------------------------------------------------------------------- /chapter13/booking_system/apis/userorders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/apis/userorders/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/apis/userorders/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_userorders = APIRouter(prefix='/api/v1', tags=["用户订单模块"]) 3 | from apis.userorders.api import refund_reserve_order, unpay_reserve_order, user_order_info, user_order_list, \ 4 | wxauth_login 5 | -------------------------------------------------------------------------------- /chapter13/booking_system/apis/userorders/api/user_order_list.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from db.async_database import depends_get_db_session 3 | from db.async_database import AsyncSession 4 | from exts.responses.json_response import Success, Fail 5 | from ..api import router_userorders 6 | from ..schemas import UserOrderIonfoListForm 7 | from ..repository import Serveries 8 | 9 | @router_userorders.post("/user_order_list", summary='用户自己订单列表') 10 | async def callbadk(forms: UserOrderIonfoListForm, db_session: AsyncSession = Depends(depends_get_db_session)): 11 | # 检测用户的有消息 12 | # 判断当前用户是否已经被拉黑啦,禁用了! 13 | result = await Serveries.get_order_info_list_by_visit_uopenid_select(db_session,visit_uopenid=forms.visit_uopenid,statue=forms.statue) 14 | # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 15 | return Success(api_code=200, result=result, message='查询成功') if result else Fail(api_code=200, result=None, message='无此订单状态列表信息!') 16 | -------------------------------------------------------------------------------- /chapter13/booking_system/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/config/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/db/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/exts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/exts/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/exts/requestvar/bing.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() 24 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/responses/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | ------------------------------------------------- 5 | 文件名称 : __init__.py 6 | 文件功能描述 : 功能描述 7 | 创建人 : 小钟同学 8 | 创建时间 : 2021/9/23 9 | ------------------------------------------------- 10 | 修改描述-2021/9/23: 11 | ------------------------------------------------- 12 | """ 13 | from . import json_response 14 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | import logging 4 | 5 | from exts.wechatpy.client import WeChatClient # NOQA 6 | from exts.wechatpy.component import ComponentOAuth, WeChatComponent # NOQA 7 | from exts.wechatpy.exceptions import WeChatClientException, WeChatException, WeChatOAuthException, WeChatPayException # NOQA 8 | from exts.wechatpy.oauth import WeChatOAuth # NOQA 9 | from exts.wechatpy.parser import parse_message # NOQA 10 | from exts.wechatpy.pay import WeChatPay # NOQA 11 | from exts.wechatpy.replies import create_reply # NOQA 12 | 13 | __version__ = '1.8.2' 14 | __author__ = 'messense' 15 | 16 | # Set default logging handler to avoid "No handler found" warnings. 17 | try: # Python 2.7+ 18 | from logging import NullHandler 19 | except ImportError: 20 | class NullHandler(logging.Handler): 21 | def emit(self, record): 22 | pass 23 | 24 | logging.getLogger(__name__).addHandler(NullHandler()) 25 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/_compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | wechatpy._compat 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | This module makes it easy for wechatpy to run on both Python 2 and 3. 7 | 8 | :copyright: (c) 2014 by messense. 9 | :license: MIT, see LICENSE for more details. 10 | """ 11 | from __future__ import absolute_import, unicode_literals 12 | import sys 13 | import six 14 | import warnings 15 | 16 | warnings.warn("Module `wechatpy._compat` is deprecated, will be removed in 2.0" 17 | "use `wechatpy.utils` instead", 18 | DeprecationWarning, stacklevel=2) 19 | 20 | from exts.wechatpy.utils import get_querystring 21 | from exts.wechatpy.utils import json 22 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/client/api/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class BaseWeChatAPI(object): 6 | """ WeChat API base class """ 7 | 8 | def __init__(self, client=None): 9 | self._client = client 10 | 11 | def _get(self, url, **kwargs): 12 | if getattr(self, 'API_BASE_URL', None): 13 | kwargs['api_base_url'] = self.API_BASE_URL 14 | return self._client.get(url, **kwargs) 15 | 16 | def _post(self, url, **kwargs): 17 | if getattr(self, 'API_BASE_URL', None): 18 | kwargs['api_base_url'] = self.API_BASE_URL 19 | 20 | print("当前URL",url) 21 | return self._client.post(url, **kwargs) 22 | 23 | @property 24 | def access_token(self): 25 | return self._client.access_token 26 | 27 | @property 28 | def session(self): 29 | return self._client.session 30 | 31 | @property 32 | def appid(self): 33 | return self._client.appid 34 | 35 | @property 36 | def secret(self): 37 | return self._client.secret 38 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/client/api/merchant/category.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantCategory(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def get_sub_categories(self, cate_id): 11 | res = self._post( 12 | 'merchant/category/getsub', 13 | data={'cate_id': cate_id}, 14 | result_processor=lambda x: x['cate_list'] 15 | ) 16 | return res 17 | 18 | def get_sku_list(self, cate_id): 19 | res = self._post( 20 | 'merchant/category/getsku', 21 | data={'cate_id': cate_id}, 22 | result_processor=lambda x: x['sku_table'] 23 | ) 24 | return res 25 | 26 | def get_properties(self, cate_id): 27 | res = self._post( 28 | 'merchant/category/getproperty', 29 | data={'cate_id': cate_id}, 30 | result_processor=lambda x: x['properties'] 31 | ) 32 | return res 33 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/client/api/merchant/common.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantCommon(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def upload_image(self, filename, image_data): 11 | res = self._post( 12 | 'merchant/common/upload_img', 13 | params={ 14 | 'filename': filename 15 | }, 16 | data=image_data, 17 | result_processor=lambda x: x['image_url'] 18 | ) 19 | return res 20 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/client/api/merchant/stock.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantStock(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def add(self, product_id, quantity, sku_info=''): 11 | return self._post( 12 | 'merchant/stock/add', 13 | data={ 14 | 'product_id': product_id, 15 | 'quantity': quantity, 16 | 'sku_info': sku_info 17 | } 18 | ) 19 | 20 | def reduce(self, product_id, quantity, sku_info=''): 21 | return self._post( 22 | 'merchant/stock/reduce', 23 | data={ 24 | 'product_id': product_id, 25 | 'quantity': quantity, 26 | 'sku_info': sku_info 27 | } 28 | ) 29 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/crypto/cryptography.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 4 | from cryptography.hazmat.backends import default_backend 5 | 6 | 7 | class WeChatCipher(object): 8 | 9 | def __init__(self, key, iv=None): 10 | iv = iv or key[:16] 11 | backend = default_backend() 12 | self.cipher = Cipher( 13 | algorithms.AES(key), 14 | modes.CBC(iv), 15 | backend=backend 16 | ) 17 | 18 | def encrypt(self, plaintext): 19 | encryptor = self.cipher.encryptor() 20 | return encryptor.update(plaintext) + encryptor.finalize() 21 | 22 | def decrypt(self, ciphertext): 23 | decryptor = self.cipher.decryptor() 24 | return decryptor.update(ciphertext) + decryptor.finalize() 25 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/crypto/pkcs7.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.utils import to_binary, byte2int 4 | 5 | 6 | class PKCS7Encoder(object): 7 | block_size = 32 8 | 9 | @classmethod 10 | def encode(cls, text): 11 | length = len(text) 12 | padding_count = cls.block_size - length % cls.block_size 13 | if padding_count == 0: 14 | padding_count = cls.block_size 15 | padding = to_binary(chr(padding_count)) 16 | return text + padding * padding_count 17 | 18 | @classmethod 19 | def decode(cls, decrypted): 20 | padding = byte2int(decrypted[-1]) 21 | if padding < 1 or padding > 32: 22 | padding = 0 23 | return decrypted[:-padding] 24 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/crypto/pycrypto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from Crypto.Cipher import AES 4 | 5 | 6 | class WeChatCipher(object): 7 | 8 | def __init__(self, key, iv=None): 9 | iv = iv or key[:16] 10 | self.cipher = AES.new(key, AES.MODE_CBC, iv) 11 | 12 | def encrypt(self, plaintext): 13 | return self.cipher.encrypt(plaintext) 14 | 15 | def decrypt(self, ciphertext): 16 | return self.cipher.decrypt(ciphertext) 17 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/enterprise/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.enterprise.client import WeChatClient # NOQA 5 | from exts.wechatpy.enterprise.crypto import WeChatCrypto # NOQA 6 | from exts.wechatpy.enterprise.parser import parse_message # NOQA 7 | from exts.wechatpy.enterprise.replies import create_reply # NOQA 8 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/enterprise/client/api/misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.client.api.base import BaseWeChatAPI 5 | 6 | 7 | class WeChatMisc(BaseWeChatAPI): 8 | 9 | def get_wechat_ips(self): 10 | """ 11 | 获取企业微信服务器的ip段 12 | 13 | https://work.weixin.qq.com/api/doc#90000/90135/90238/%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84ip%E6%AE%B5 14 | 15 | :return: 企业微信回调的IP段 16 | """ 17 | res = self._get('getcallbackip') 18 | return res['ip_list'] 19 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.client.api.base import BaseWeChatAPI 5 | 6 | 7 | class WeChatShakeAround(BaseWeChatAPI): 8 | 9 | def get_shake_info(self, ticket): 10 | """ 11 | 获取摇周边的设备及用户信息 12 | 13 | https://qydev.weixin.qq.com/wiki/index.php?title=获取设备及用户信息 14 | 15 | :param ticket: 摇周边业务的ticket,可在摇到的 URL 中得到,ticket 生效时间为30分钟 16 | :return: 设备及用户信息 17 | """ 18 | res = self._post( 19 | 'shakearound/getshakeinfo', 20 | data={ 21 | 'ticket': ticket 22 | } 23 | ) 24 | return res['data'] 25 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/enterprise/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.exceptions import WeChatException 5 | 6 | 7 | class InvalidCorpIdException(WeChatException): 8 | 9 | def __init__(self, errcode=-40005, errmsg='Invalid corp_id'): 10 | super(InvalidCorpIdException, self).__init__(errcode, errmsg) 11 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/enterprise/parser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | import xmltodict 5 | 6 | from exts.wechatpy.enterprise.events import EVENT_TYPES 7 | from exts.wechatpy.enterprise.messages import MESSAGE_TYPES 8 | from exts.wechatpy.messages import UnknownMessage 9 | from exts.wechatpy.utils import to_text 10 | 11 | 12 | def parse_message(xml): 13 | if not xml: 14 | return 15 | message = xmltodict.parse(to_text(xml))['xml'] 16 | message_type = message['MsgType'].lower() 17 | if message_type == 'event': 18 | event_type = message['Event'].lower() 19 | message_class = EVENT_TYPES.get(event_type, UnknownMessage) 20 | else: 21 | message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) 22 | return message_class(message) 23 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/pay/api/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.pay.api.redpack import WeChatRedpack # NOQA 4 | from exts.wechatpy.pay.api.transfer import WeChatTransfer # NOQA 5 | from exts.wechatpy.pay.api.coupon import WeChatCoupon # NOQA 6 | from exts.wechatpy.pay.api.order import WeChatOrder # NOQA 7 | from exts.wechatpy.pay.api.refund import WeChatRefund # NOQA 8 | from exts.wechatpy.pay.api.tools import WeChatTools # NOQA 9 | from exts.wechatpy.pay.api.jsapi import WeChatJSAPI # NOQA 10 | from exts.wechatpy.pay.api.micropay import WeChatMicroPay # NOQA 11 | from exts.wechatpy.pay.api.withhold import WeChatWithhold # NOQA 12 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/pay/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class BaseWeChatPayAPI(object): 6 | """ WeChat Pay API base class """ 7 | def __init__(self, client=None): 8 | self._client = client 9 | 10 | def _get(self, url, **kwargs): 11 | if getattr(self, 'API_BASE_URL', None): 12 | kwargs['api_base_url'] = self.API_BASE_URL 13 | return self._client.get(url, **kwargs) 14 | 15 | def _post(self, url, **kwargs): 16 | if getattr(self, 'API_BASE_URL', None): 17 | kwargs['api_base_url'] = self.API_BASE_URL 18 | return self._client.post(url, **kwargs) 19 | 20 | @property 21 | def appid(self): 22 | return self._client.appid 23 | 24 | @property 25 | def sub_appid(self): 26 | return self._client.sub_appid 27 | 28 | @property 29 | def mch_id(self): 30 | return self._client.mch_id 31 | 32 | @property 33 | def sub_mch_id(self): 34 | return self._client.sub_mch_id 35 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/session/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class SessionStorage(object): 6 | 7 | def get(self, key, default=None): 8 | raise NotImplementedError() 9 | 10 | def set(self, key, value, ttl=None): 11 | raise NotImplementedError() 12 | 13 | def delete(self, key): 14 | raise NotImplementedError() 15 | 16 | def __getitem__(self, key): 17 | self.get(key) 18 | 19 | def __setitem__(self, key, value): 20 | self.set(key, value) 21 | 22 | def __delitem__(self, key): 23 | self.delete(key) 24 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/session/memorystorage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.session import SessionStorage 4 | 5 | 6 | class MemoryStorage(SessionStorage): 7 | 8 | def __init__(self): 9 | self._data = {} 10 | 11 | def get(self, key, default=None): 12 | return self._data.get(key, default) 13 | 14 | def set(self, key, value, ttl=None): 15 | if value is None: 16 | return 17 | self._data[key] = value 18 | 19 | def delete(self, key): 20 | self._data.pop(key, None) 21 | -------------------------------------------------------------------------------- /chapter13/booking_system/exts/wechatpy/session/shovestorage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.session import SessionStorage 4 | 5 | 6 | class ShoveStorage(SessionStorage): 7 | 8 | def __init__(self, shove, prefix='wechatpy'): 9 | self.shove = shove 10 | self.prefix = prefix 11 | 12 | def key_name(self, key): 13 | return '{0}:{1}'.format(self.prefix, key) 14 | 15 | def get(self, key, default=None): 16 | key = self.key_name(key) 17 | try: 18 | return self.shove[key] 19 | except KeyError: 20 | return default 21 | 22 | def set(self, key, value, ttl=None): 23 | if value is None: 24 | return 25 | 26 | key = self.key_name(key) 27 | self.shove[key] = value 28 | 29 | def delete(self, key): 30 | key = self.key_name(key) 31 | try: 32 | del self.shove[key] 33 | except KeyError: 34 | pass 35 | -------------------------------------------------------------------------------- /chapter13/booking_system/main.py: -------------------------------------------------------------------------------- 1 | from app import creat_app 2 | app =creat_app() 3 | if __name__ == "__main__": 4 | import uvicorn 5 | import os 6 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 7 | print(app_modeel_name) 8 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 9 | 10 | 11 | # tree -I "node_modules|cache|test_*" 12 | # tree -I "__pycache__" -------------------------------------------------------------------------------- /chapter13/booking_system/middlewares/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/middlewares/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/middlewares/loger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/middlewares/loger/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/middlewares/loger/bing.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() 24 | -------------------------------------------------------------------------------- /chapter13/booking_system/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/plugins/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/plugins/base.py: -------------------------------------------------------------------------------- 1 | import fastapi 2 | import pydantic 3 | import typing 4 | import abc 5 | 6 | class PluginBase(abc.ABC): 7 | 8 | def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): 9 | if app is not None: 10 | self.init_app(app) 11 | 12 | @abc.abstractmethod 13 | def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: 14 | raise NotImplementedError('需要实现初始化') 15 | -------------------------------------------------------------------------------- /chapter13/booking_system/requirements.txt: -------------------------------------------------------------------------------- 1 | aio-pika==8.0.3 2 | aiormq==6.3.4 3 | anyio==3.6.1 4 | asgiref==3.5.2 5 | asyncpg==0.26.0 6 | certifi==2022.6.15 7 | charset-normalizer==2.1.0 8 | click==8.1.3 9 | colorama==0.4.5 10 | dnspython==2.2.1 11 | email-validator==1.2.1 12 | fastapi==0.79.0 13 | greenlet==1.1.2 14 | gunicorn==20.1.0 15 | h11==0.13.0 16 | httptools==0.4.0 17 | idna==3.3 18 | itsdangerous==2.1.2 19 | Jinja2==3.1.2 20 | MarkupSafe==2.1.1 21 | multidict==6.0.2 22 | optionaldict==0.1.2 23 | orjson==3.7.8 24 | pamqp==3.2.0 25 | pika==1.3.0 26 | psycopg2==2.9.3 27 | pycryptodome==3.15.0 28 | pydantic==1.9.1 29 | python-dotenv==0.20.0 30 | python-multipart==0.0.5 31 | PyYAML==6.0 32 | requests==2.28.1 33 | six==1.16.0 34 | sniffio==1.2.0 35 | SQLAlchemy==1.4.39 36 | starlette==0.19.1 37 | typing_extensions==4.3.0 38 | ujson==5.4.0 39 | urllib3==1.26.10 40 | uvicorn==0.17.6 41 | watchgod==0.8.2 42 | websockets==10.3 43 | xmltodict==0.13.0 44 | yarl==1.7.2 45 | -------------------------------------------------------------------------------- /chapter13/booking_system/testcase/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/testcase/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/testcase/test_async_api_v2.py: -------------------------------------------------------------------------------- 1 | # from uuid import UUID 2 | # 3 | import pytest 4 | from httpx import AsyncClient 5 | pytestmark = pytest.mark.anyio 6 | 7 | async def test_hospital_info(async_client: AsyncClient): 8 | response = await async_client.get("/api/v1/hospital_info") 9 | print('response', response.text) 10 | assert response.status_code == 200 11 | 12 | 13 | async def test_doctor_list(async_client: AsyncClient): 14 | response = await async_client.get("/api/v1/doctor_list") 15 | print('response', response.text) 16 | assert response.status_code == 200 -------------------------------------------------------------------------------- /chapter13/booking_system/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/utils/__init__.py -------------------------------------------------------------------------------- /chapter13/booking_system/utils/cast_helper.py: -------------------------------------------------------------------------------- 1 | def add(a,b): 2 | return a+b; -------------------------------------------------------------------------------- /chapter13/booking_system/utils/run_with_asyncio.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import asyncio 3 | from functools import wraps 4 | from typing import Any, Awaitable, Callable, TypeVar 5 | T = TypeVar("T") 6 | __all__ = ["run_with_asyncio"] 7 | def run_with_asyncio(f: Callable[..., Awaitable[T]]) -> Callable[..., T]: 8 | @wraps(f) 9 | def wrapper(*args: Any, **kwargs: Any) -> T: 10 | print("pajinlail") 11 | return asyncio.run(f(*args, **kwargs)) 12 | return wrapper -------------------------------------------------------------------------------- /chapter13/booking_system/wxchatsdk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/booking_system/wxchatsdk/__init__.py -------------------------------------------------------------------------------- /chapter13/pytest_demo/cast_helper.py: -------------------------------------------------------------------------------- 1 | def add(a,b): 2 | return a+b; -------------------------------------------------------------------------------- /chapter13/pytest_demo/test_add.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from cast_helper import add 3 | 4 | 5 | class TestMyAddClass: 6 | 7 | 8 | def setup(self): 9 | print("setup前置条件") 10 | 11 | def teardown(self): 12 | print("teardown后置条件") 13 | 14 | def setup_class(self): 15 | print("前置条件") 16 | 17 | def teardown_class(self): 18 | print("后置条件") 19 | 20 | def test_add(self): 21 | assert 3 == 3 22 | 23 | def test_add_v2(self): 24 | assert 3 == 5 25 | 26 | if __name__ == "__main__": 27 | pytest.main(['-q']) 28 | -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/testcase/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(scope="session", autouse=True) 5 | def action_01(): 6 | print("session-类型作用域-前置条件") 7 | yield 8 | print("session-类型作用域-后置条件") 9 | 10 | 11 | @pytest.fixture(scope="module", autouse=True) 12 | def action_02(): 13 | print("module-类型作用域-前置条件") 14 | yield 15 | print("module-类型作用域-后置条件") 16 | 17 | 18 | # 生效的范围,类级别,每个类才会执行一次 19 | @pytest.fixture(scope="class", autouse=True) 20 | def action_03(): 21 | print("class-类型作用域-前置条件") 22 | yield 23 | print("class-类型作用域-后置条件") 24 | 25 | -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/testcase/test_case1.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | def test_get_user_role(action_01): 4 | print(f"获取当前用户角色:{action_01}") 5 | 6 | if __name__ == "__main__": 7 | pytest.main() -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter13/pytest_fixture_demo/tests/__init__.py -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/tests/test_fixs.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def setup(): 5 | print('setup 用例开始前执行') 6 | 7 | def teardown(): 8 | print('teardown 用例结束后执行') 9 | 10 | # 定义一个前后置方法 11 | @pytest.fixture 12 | def my_first_fixture(): 13 | print("前置方法") 14 | yield 15 | print("后置方法") 16 | 17 | 18 | # 定义测试用例 19 | def test_cast_1(my_first_fixture): 20 | print("开始执行cast_1测试用例") 21 | assert 3 == 3 22 | 23 | 24 | # 定义测试用例 25 | def test_cast_2(my_first_fixture): 26 | print("开始执行cast_2测试用例") 27 | assert 3 == 3 28 | 29 | 30 | if __name__ == "__main__": 31 | pytest.main() 32 | -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/tests/test_fixs_parametrize.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # 字典列表 4 | data = ["superadmin", "admin", "common"] 5 | data2 = ["superadmin2", "admin2", "common2"] 6 | 7 | @pytest.mark.parametrize("request_data", data) 8 | def test_get_user_role(request_data): 9 | print(f"获取当前用户角色:{request_data}") 10 | 11 | @pytest.mark.parametrize("data",data) 12 | @pytest.mark.parametrize("data2",data2) 13 | def test_a(data,data2): 14 | print(f"测试参数组合,data:{data},data2:{data}") 15 | 16 | 17 | if __name__ == "__main__": 18 | pytest.main() 19 | -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/tests/test_fixs_parametrize_class.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.parametrize("role_name,age", [("superadmin",45), ("admin",4), ("common",6)]) 5 | class TestGetUserRole: 6 | def test_get_user_role(self,role_name,age): 7 | print(f"获取当前用户角色:{role_name,age}") 8 | 9 | if __name__ == "__main__": 10 | pytest.main() -------------------------------------------------------------------------------- /chapter13/pytest_fixture_demo/tests/test_fixs_params.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | data = ["superadmin", "admin","common"] 4 | 5 | @pytest.fixture(scope="function",name='user_role_fixture', params=data,autouse=True) 6 | def user_role(request): 7 | print("当前用例使用的参数:",request.param) 8 | return request.param 9 | 10 | def test_get_user_role(user_role_fixture): 11 | print(f"获取当前用户角色:{user_role_fixture}") 12 | 13 | 14 | if __name__ == "__main__": 15 | pytest.main() -------------------------------------------------------------------------------- /chapter13/unittest_demo/main.py: -------------------------------------------------------------------------------- 1 | # unittest导入 2 | import unittest 3 | 4 | # 定义测试类 5 | class UnitTestForAdd(unittest.TestCase): 6 | # 测试用例运行之前 7 | def setUp(self) -> None: 8 | print('前置条件') 9 | 10 | # 测试用例运行之后 11 | def tearDown(self) -> None: 12 | print('后置条件') 13 | # 定义测试用例 14 | 15 | 16 | def test_add(self): 17 | self.assertEqual(3,3) 18 | 19 | if __name__ == '__main__': 20 | unittest.main() -------------------------------------------------------------------------------- /chapter14/booking_system/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | ENV ASYNC_DB_DRIVER=postgresql+asyncpg SYNC_DB_DRIVER=postgresql DB_PASSWORD=123456 3 | COPY ./requirements.txt ./requirements.txt 4 | RUN pip install --upgrade -r ./requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple 5 | COPY ./ . 6 | 7 | CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "12510"] 8 | -------------------------------------------------------------------------------- /chapter14/booking_system/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/apis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/apis/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/apis/doctor/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_docrot = APIRouter(prefix='/api/v1',tags=["医生信息模块"],include_in_schema=True) 3 | from ..api import doctor_api -------------------------------------------------------------------------------- /chapter14/booking_system/apis/doctor/dependencies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/apis/doctor/dependencies/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/apis/doctor/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SchedulingInfo(BaseModel): 5 | # 预约医生编号 6 | dno: str 7 | # 预约时间 8 | start_time: str = None 9 | 10 | 11 | class MakeReserveOrderForm(BaseModel): 12 | # 预约医生编号 13 | dno: str 14 | # 预约医生排号时段 15 | nsindex: str 16 | 17 | 18 | class PayReserveOrderForm(BaseModel): 19 | # 预约医生编号 20 | dno: str 21 | # 预约医生排号时段 22 | nsindex: str 23 | # 预约人信息 24 | visit_uname: str 25 | visit_uphone: str 26 | visit_uopenid: str = None 27 | visit_usex: str 28 | visit_uage: str 29 | -------------------------------------------------------------------------------- /chapter14/booking_system/apis/hospital/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/apis/hospital/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/apis/hospital/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_hospital = APIRouter(prefix='/api/v1',tags=["医院信息模块"]) 3 | # 導入模塊 4 | from apis.hospital.api import get_hospital_info -------------------------------------------------------------------------------- /chapter14/booking_system/apis/hospital/api/get_hospital_info.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from apis.hospital.repository import HospitalServeries 3 | from db.async_database import depends_get_db_session 4 | from db.async_database import AsyncSession 5 | from exts.responses.json_response import Success 6 | from ..api import router_hospital 7 | 8 | 9 | @router_hospital.get("/hospital_info", summary='获取医院信息') 10 | async def callbadk(db_session: AsyncSession = Depends(depends_get_db_session)): 11 | info = await HospitalServeries.get_hospital_info(db_session, id=1) 12 | return Success(result=info) 13 | -------------------------------------------------------------------------------- /chapter14/booking_system/apis/hospital/repository/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import select, update, delete 2 | from sqlalchemy.ext.asyncio import AsyncSession 3 | from db.models import Hospitalinfo 4 | from db.async_database import async_engine, Base 5 | 6 | 7 | class HospitalServeries: 8 | 9 | @staticmethod 10 | async def get_hospital_info(async_session: AsyncSession, id: int): 11 | _result = await async_session.execute( 12 | select(Hospitalinfo.name, Hospitalinfo.describe, Hospitalinfo.describeimages).where(Hospitalinfo.id == id)) 13 | scalars_result = _result.first() 14 | # scalars_result = _result.scalars().first() 15 | return scalars_result 16 | -------------------------------------------------------------------------------- /chapter14/booking_system/apis/payorders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/apis/payorders/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/apis/payorders/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_payorders = APIRouter(prefix='/api/v1',tags=["支付订单模块"]) 3 | from apis.payorders.api import doctor_reserve_order 4 | from apis.payorders.api import payback_reserve_order 5 | from apis.payorders.api import reserve_order_info 6 | from apis.payorders.api import doctor_reserve_reorder 7 | from apis.payorders.api import doctor_order_check -------------------------------------------------------------------------------- /chapter14/booking_system/apis/payorders/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | from starlette.requests import Request 2 | 3 | def get_client_ip(request: Request): 4 | """ 5 | 获取客户端真实ip 6 | :param request: 7 | :return: 8 | """ 9 | forwarded = request.headers.get("X-Forwarded-For") 10 | if forwarded: 11 | return forwarded.split(",")[0] 12 | return request.client.host -------------------------------------------------------------------------------- /chapter14/booking_system/apis/userorders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/apis/userorders/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/apis/userorders/api/__init__.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | router_userorders = APIRouter(prefix='/api/v1', tags=["用户订单模块"]) 3 | from apis.userorders.api import refund_reserve_order, unpay_reserve_order, user_order_info, user_order_list, \ 4 | wxauth_login 5 | -------------------------------------------------------------------------------- /chapter14/booking_system/apis/userorders/api/user_order_list.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from db.async_database import depends_get_db_session 3 | from db.async_database import AsyncSession 4 | from exts.responses.json_response import Success, Fail 5 | from ..api import router_userorders 6 | from ..schemas import UserOrderIonfoListForm 7 | from ..repository import Serveries 8 | 9 | @router_userorders.post("/user_order_list", summary='用户自己订单列表') 10 | async def callbadk(forms: UserOrderIonfoListForm, db_session: AsyncSession = Depends(depends_get_db_session)): 11 | # 检测用户的有消息 12 | # 判断当前用户是否已经被拉黑啦,禁用了! 13 | result = await Serveries.get_order_info_list_by_visit_uopenid_select(db_session,visit_uopenid=forms.visit_uopenid,statue=forms.statue) 14 | # is_reserve -属性 1:表示可以点击预约 2:有排班记录,但是已预约满 15 | return Success(api_code=200, result=result, message='查询成功') if result else Fail(api_code=200, result=None, message='无此订单状态列表信息!') 16 | -------------------------------------------------------------------------------- /chapter14/booking_system/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/config/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/db/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/exts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/exts/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/exts/requestvar/bing.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() 24 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/responses/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/evn python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | ------------------------------------------------- 5 | 文件名称 : __init__.py 6 | 文件功能描述 : 功能描述 7 | 创建人 : 小钟同学 8 | 创建时间 : 2021/9/23 9 | ------------------------------------------------- 10 | 修改描述-2021/9/23: 11 | ------------------------------------------------- 12 | """ 13 | from . import json_response 14 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | import logging 4 | 5 | from exts.wechatpy.client import WeChatClient # NOQA 6 | from exts.wechatpy.component import ComponentOAuth, WeChatComponent # NOQA 7 | from exts.wechatpy.exceptions import WeChatClientException, WeChatException, WeChatOAuthException, WeChatPayException # NOQA 8 | from exts.wechatpy.oauth import WeChatOAuth # NOQA 9 | from exts.wechatpy.parser import parse_message # NOQA 10 | from exts.wechatpy.pay import WeChatPay # NOQA 11 | from exts.wechatpy.replies import create_reply # NOQA 12 | 13 | __version__ = '1.8.2' 14 | __author__ = 'messense' 15 | 16 | # Set default logging handler to avoid "No handler found" warnings. 17 | try: # Python 2.7+ 18 | from logging import NullHandler 19 | except ImportError: 20 | class NullHandler(logging.Handler): 21 | def emit(self, record): 22 | pass 23 | 24 | logging.getLogger(__name__).addHandler(NullHandler()) 25 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/_compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | wechatpy._compat 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | This module makes it easy for wechatpy to run on both Python 2 and 3. 7 | 8 | :copyright: (c) 2014 by messense. 9 | :license: MIT, see LICENSE for more details. 10 | """ 11 | from __future__ import absolute_import, unicode_literals 12 | import sys 13 | import six 14 | import warnings 15 | 16 | warnings.warn("Module `wechatpy._compat` is deprecated, will be removed in 2.0" 17 | "use `wechatpy.utils` instead", 18 | DeprecationWarning, stacklevel=2) 19 | 20 | from exts.wechatpy.utils import get_querystring 21 | from exts.wechatpy.utils import json 22 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/client/api/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class BaseWeChatAPI(object): 6 | """ WeChat API base class """ 7 | 8 | def __init__(self, client=None): 9 | self._client = client 10 | 11 | def _get(self, url, **kwargs): 12 | if getattr(self, 'API_BASE_URL', None): 13 | kwargs['api_base_url'] = self.API_BASE_URL 14 | return self._client.get(url, **kwargs) 15 | 16 | def _post(self, url, **kwargs): 17 | if getattr(self, 'API_BASE_URL', None): 18 | kwargs['api_base_url'] = self.API_BASE_URL 19 | 20 | print("当前URL",url) 21 | return self._client.post(url, **kwargs) 22 | 23 | @property 24 | def access_token(self): 25 | return self._client.access_token 26 | 27 | @property 28 | def session(self): 29 | return self._client.session 30 | 31 | @property 32 | def appid(self): 33 | return self._client.appid 34 | 35 | @property 36 | def secret(self): 37 | return self._client.secret 38 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/client/api/merchant/category.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantCategory(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def get_sub_categories(self, cate_id): 11 | res = self._post( 12 | 'merchant/category/getsub', 13 | data={'cate_id': cate_id}, 14 | result_processor=lambda x: x['cate_list'] 15 | ) 16 | return res 17 | 18 | def get_sku_list(self, cate_id): 19 | res = self._post( 20 | 'merchant/category/getsku', 21 | data={'cate_id': cate_id}, 22 | result_processor=lambda x: x['sku_table'] 23 | ) 24 | return res 25 | 26 | def get_properties(self, cate_id): 27 | res = self._post( 28 | 'merchant/category/getproperty', 29 | data={'cate_id': cate_id}, 30 | result_processor=lambda x: x['properties'] 31 | ) 32 | return res 33 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/client/api/merchant/common.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantCommon(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def upload_image(self, filename, image_data): 11 | res = self._post( 12 | 'merchant/common/upload_img', 13 | params={ 14 | 'filename': filename 15 | }, 16 | data=image_data, 17 | result_processor=lambda x: x['image_url'] 18 | ) 19 | return res 20 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/client/api/merchant/stock.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.client.api.base import BaseWeChatAPI 4 | 5 | 6 | class MerchantStock(BaseWeChatAPI): 7 | 8 | API_BASE_URL = 'https://api.weixin.qq.com/' 9 | 10 | def add(self, product_id, quantity, sku_info=''): 11 | return self._post( 12 | 'merchant/stock/add', 13 | data={ 14 | 'product_id': product_id, 15 | 'quantity': quantity, 16 | 'sku_info': sku_info 17 | } 18 | ) 19 | 20 | def reduce(self, product_id, quantity, sku_info=''): 21 | return self._post( 22 | 'merchant/stock/reduce', 23 | data={ 24 | 'product_id': product_id, 25 | 'quantity': quantity, 26 | 'sku_info': sku_info 27 | } 28 | ) 29 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/crypto/cryptography.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 4 | from cryptography.hazmat.backends import default_backend 5 | 6 | 7 | class WeChatCipher(object): 8 | 9 | def __init__(self, key, iv=None): 10 | iv = iv or key[:16] 11 | backend = default_backend() 12 | self.cipher = Cipher( 13 | algorithms.AES(key), 14 | modes.CBC(iv), 15 | backend=backend 16 | ) 17 | 18 | def encrypt(self, plaintext): 19 | encryptor = self.cipher.encryptor() 20 | return encryptor.update(plaintext) + encryptor.finalize() 21 | 22 | def decrypt(self, ciphertext): 23 | decryptor = self.cipher.decryptor() 24 | return decryptor.update(ciphertext) + decryptor.finalize() 25 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/crypto/pkcs7.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.utils import to_binary, byte2int 4 | 5 | 6 | class PKCS7Encoder(object): 7 | block_size = 32 8 | 9 | @classmethod 10 | def encode(cls, text): 11 | length = len(text) 12 | padding_count = cls.block_size - length % cls.block_size 13 | if padding_count == 0: 14 | padding_count = cls.block_size 15 | padding = to_binary(chr(padding_count)) 16 | return text + padding * padding_count 17 | 18 | @classmethod 19 | def decode(cls, decrypted): 20 | padding = byte2int(decrypted[-1]) 21 | if padding < 1 or padding > 32: 22 | padding = 0 23 | return decrypted[:-padding] 24 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/crypto/pycrypto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from Crypto.Cipher import AES 4 | 5 | 6 | class WeChatCipher(object): 7 | 8 | def __init__(self, key, iv=None): 9 | iv = iv or key[:16] 10 | self.cipher = AES.new(key, AES.MODE_CBC, iv) 11 | 12 | def encrypt(self, plaintext): 13 | return self.cipher.encrypt(plaintext) 14 | 15 | def decrypt(self, ciphertext): 16 | return self.cipher.decrypt(ciphertext) 17 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/enterprise/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.enterprise.client import WeChatClient # NOQA 5 | from exts.wechatpy.enterprise.crypto import WeChatCrypto # NOQA 6 | from exts.wechatpy.enterprise.parser import parse_message # NOQA 7 | from exts.wechatpy.enterprise.replies import create_reply # NOQA 8 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/enterprise/client/api/misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.client.api.base import BaseWeChatAPI 5 | 6 | 7 | class WeChatMisc(BaseWeChatAPI): 8 | 9 | def get_wechat_ips(self): 10 | """ 11 | 获取企业微信服务器的ip段 12 | 13 | https://work.weixin.qq.com/api/doc#90000/90135/90238/%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84ip%E6%AE%B5 14 | 15 | :return: 企业微信回调的IP段 16 | """ 17 | res = self._get('getcallbackip') 18 | return res['ip_list'] 19 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/enterprise/client/api/shakearound.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.client.api.base import BaseWeChatAPI 5 | 6 | 7 | class WeChatShakeAround(BaseWeChatAPI): 8 | 9 | def get_shake_info(self, ticket): 10 | """ 11 | 获取摇周边的设备及用户信息 12 | 13 | https://qydev.weixin.qq.com/wiki/index.php?title=获取设备及用户信息 14 | 15 | :param ticket: 摇周边业务的ticket,可在摇到的 URL 中得到,ticket 生效时间为30分钟 16 | :return: 设备及用户信息 17 | """ 18 | res = self._post( 19 | 'shakearound/getshakeinfo', 20 | data={ 21 | 'ticket': ticket 22 | } 23 | ) 24 | return res['data'] 25 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/enterprise/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from exts.wechatpy.exceptions import WeChatException 5 | 6 | 7 | class InvalidCorpIdException(WeChatException): 8 | 9 | def __init__(self, errcode=-40005, errmsg='Invalid corp_id'): 10 | super(InvalidCorpIdException, self).__init__(errcode, errmsg) 11 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/enterprise/parser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | import xmltodict 5 | 6 | from exts.wechatpy.enterprise.events import EVENT_TYPES 7 | from exts.wechatpy.enterprise.messages import MESSAGE_TYPES 8 | from exts.wechatpy.messages import UnknownMessage 9 | from exts.wechatpy.utils import to_text 10 | 11 | 12 | def parse_message(xml): 13 | if not xml: 14 | return 15 | message = xmltodict.parse(to_text(xml))['xml'] 16 | message_type = message['MsgType'].lower() 17 | if message_type == 'event': 18 | event_type = message['Event'].lower() 19 | message_class = EVENT_TYPES.get(event_type, UnknownMessage) 20 | else: 21 | message_class = MESSAGE_TYPES.get(message_type, UnknownMessage) 22 | return message_class(message) 23 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/pay/api/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.pay.api.redpack import WeChatRedpack # NOQA 4 | from exts.wechatpy.pay.api.transfer import WeChatTransfer # NOQA 5 | from exts.wechatpy.pay.api.coupon import WeChatCoupon # NOQA 6 | from exts.wechatpy.pay.api.order import WeChatOrder # NOQA 7 | from exts.wechatpy.pay.api.refund import WeChatRefund # NOQA 8 | from exts.wechatpy.pay.api.tools import WeChatTools # NOQA 9 | from exts.wechatpy.pay.api.jsapi import WeChatJSAPI # NOQA 10 | from exts.wechatpy.pay.api.micropay import WeChatMicroPay # NOQA 11 | from exts.wechatpy.pay.api.withhold import WeChatWithhold # NOQA 12 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/pay/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class BaseWeChatPayAPI(object): 6 | """ WeChat Pay API base class """ 7 | def __init__(self, client=None): 8 | self._client = client 9 | 10 | def _get(self, url, **kwargs): 11 | if getattr(self, 'API_BASE_URL', None): 12 | kwargs['api_base_url'] = self.API_BASE_URL 13 | return self._client.get(url, **kwargs) 14 | 15 | def _post(self, url, **kwargs): 16 | if getattr(self, 'API_BASE_URL', None): 17 | kwargs['api_base_url'] = self.API_BASE_URL 18 | return self._client.post(url, **kwargs) 19 | 20 | @property 21 | def appid(self): 22 | return self._client.appid 23 | 24 | @property 25 | def sub_appid(self): 26 | return self._client.sub_appid 27 | 28 | @property 29 | def mch_id(self): 30 | return self._client.mch_id 31 | 32 | @property 33 | def sub_mch_id(self): 34 | return self._client.sub_mch_id 35 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/session/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | 5 | class SessionStorage(object): 6 | 7 | def get(self, key, default=None): 8 | raise NotImplementedError() 9 | 10 | def set(self, key, value, ttl=None): 11 | raise NotImplementedError() 12 | 13 | def delete(self, key): 14 | raise NotImplementedError() 15 | 16 | def __getitem__(self, key): 17 | self.get(key) 18 | 19 | def __setitem__(self, key, value): 20 | self.set(key, value) 21 | 22 | def __delitem__(self, key): 23 | self.delete(key) 24 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/session/memorystorage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.session import SessionStorage 4 | 5 | 6 | class MemoryStorage(SessionStorage): 7 | 8 | def __init__(self): 9 | self._data = {} 10 | 11 | def get(self, key, default=None): 12 | return self._data.get(key, default) 13 | 14 | def set(self, key, value, ttl=None): 15 | if value is None: 16 | return 17 | self._data[key] = value 18 | 19 | def delete(self, key): 20 | self._data.pop(key, None) 21 | -------------------------------------------------------------------------------- /chapter14/booking_system/exts/wechatpy/session/shovestorage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | from exts.wechatpy.session import SessionStorage 4 | 5 | 6 | class ShoveStorage(SessionStorage): 7 | 8 | def __init__(self, shove, prefix='wechatpy'): 9 | self.shove = shove 10 | self.prefix = prefix 11 | 12 | def key_name(self, key): 13 | return '{0}:{1}'.format(self.prefix, key) 14 | 15 | def get(self, key, default=None): 16 | key = self.key_name(key) 17 | try: 18 | return self.shove[key] 19 | except KeyError: 20 | return default 21 | 22 | def set(self, key, value, ttl=None): 23 | if value is None: 24 | return 25 | 26 | key = self.key_name(key) 27 | self.shove[key] = value 28 | 29 | def delete(self, key): 30 | key = self.key_name(key) 31 | try: 32 | del self.shove[key] 33 | except KeyError: 34 | pass 35 | -------------------------------------------------------------------------------- /chapter14/booking_system/main.py: -------------------------------------------------------------------------------- 1 | from app import creat_app 2 | app =creat_app() 3 | if __name__ == "__main__": 4 | import uvicorn 5 | import os 6 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 7 | print(app_modeel_name) 8 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 9 | 10 | 11 | # tree -I "node_modules|cache|test_*" 12 | # tree -I "__pycache__" -------------------------------------------------------------------------------- /chapter14/booking_system/middlewares/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/middlewares/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/middlewares/loger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/middlewares/loger/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/middlewares/loger/bing.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() 24 | -------------------------------------------------------------------------------- /chapter14/booking_system/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/plugins/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/plugins/base.py: -------------------------------------------------------------------------------- 1 | import fastapi 2 | import pydantic 3 | import typing 4 | import abc 5 | 6 | class PluginBase(abc.ABC): 7 | 8 | def __init__(self,app: fastapi.FastAPI = None,config: pydantic.BaseSettings = None): 9 | if app is not None: 10 | self.init_app(app) 11 | 12 | @abc.abstractmethod 13 | def init_app(self,app: fastapi.FastAPI,config: pydantic.BaseSettings = None,*args,**kwargs) -> None: 14 | raise NotImplementedError('需要实现初始化') 15 | -------------------------------------------------------------------------------- /chapter14/booking_system/requirements.txt: -------------------------------------------------------------------------------- 1 | aio-pika==8.0.3 2 | aiormq==6.3.4 3 | anyio==3.6.1 4 | asgiref==3.5.2 5 | asyncpg==0.26.0 6 | certifi==2022.6.15 7 | charset-normalizer==2.1.0 8 | click==8.1.3 9 | colorama==0.4.5 10 | dnspython==2.2.1 11 | email-validator==1.2.1 12 | fastapi==0.79.0 13 | greenlet==1.1.2 14 | gunicorn==20.1.0 15 | h11==0.13.0 16 | httptools==0.4.0 17 | idna==3.3 18 | itsdangerous==2.1.2 19 | Jinja2==3.1.2 20 | MarkupSafe==2.1.1 21 | multidict==6.0.2 22 | optionaldict==0.1.2 23 | orjson==3.7.8 24 | pamqp==3.2.0 25 | pika==1.3.0 26 | psycopg2==2.9.3 27 | pycryptodome==3.15.0 28 | pydantic==1.9.1 29 | python-dotenv==0.20.0 30 | python-multipart==0.0.5 31 | PyYAML==6.0 32 | requests==2.28.1 33 | six==1.16.0 34 | sniffio==1.2.0 35 | SQLAlchemy==1.4.39 36 | starlette==0.19.1 37 | typing_extensions==4.3.0 38 | ujson==5.4.0 39 | urllib3==1.26.10 40 | uvicorn==0.17.6 41 | watchgod==0.8.2 42 | websockets==10.3 43 | xmltodict==0.13.0 44 | yarl==1.7.2 45 | -------------------------------------------------------------------------------- /chapter14/booking_system/testcase/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/testcase/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/testcase/test_async_api_v2.py: -------------------------------------------------------------------------------- 1 | # from uuid import UUID 2 | # 3 | import pytest 4 | from httpx import AsyncClient 5 | pytestmark = pytest.mark.anyio 6 | 7 | async def test_hospital_info(async_client: AsyncClient): 8 | response = await async_client.get("/api/v1/hospital_info") 9 | print('response', response.text) 10 | assert response.status_code == 200 11 | 12 | 13 | async def test_doctor_list(async_client: AsyncClient): 14 | response = await async_client.get("/api/v1/doctor_list") 15 | print('response', response.text) 16 | assert response.status_code == 200 -------------------------------------------------------------------------------- /chapter14/booking_system/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/utils/__init__.py -------------------------------------------------------------------------------- /chapter14/booking_system/utils/cast_helper.py: -------------------------------------------------------------------------------- 1 | def add(a,b): 2 | return a+b; -------------------------------------------------------------------------------- /chapter14/booking_system/utils/run_with_asyncio.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import asyncio 3 | from functools import wraps 4 | from typing import Any, Awaitable, Callable, TypeVar 5 | T = TypeVar("T") 6 | __all__ = ["run_with_asyncio"] 7 | def run_with_asyncio(f: Callable[..., Awaitable[T]]) -> Callable[..., T]: 8 | @wraps(f) 9 | def wrapper(*args: Any, **kwargs: Any) -> T: 10 | print("pajinlail") 11 | return asyncio.run(f(*args, **kwargs)) 12 | return wrapper -------------------------------------------------------------------------------- /chapter14/booking_system/wxchatsdk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter14/booking_system/wxchatsdk/__init__.py -------------------------------------------------------------------------------- /chapter15/Fastapi_cProfile/.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/Fastapi_cProfile/.prof -------------------------------------------------------------------------------- /chapter15/async_sync_change/main_asgiref_async_to_sync.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from fastapi import FastAPI,Request 4 | from fastapi.responses import PlainTextResponse 5 | from fastapi.params import Body 6 | 7 | 8 | app = FastAPI() 9 | 10 | 11 | @app.post("/get/access_token") 12 | def access_token(request:Request,name=Body(...)): 13 | # print(reques.body()) 14 | from asgiref.sync import async_to_sync 15 | body = async_to_sync(request.body)() 16 | print(body) 17 | return PlainTextResponse(body.decode(encoding='utf-8')) 18 | 19 | 20 | if __name__ == '__main__': 21 | import uvicorn 22 | uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) -------------------------------------------------------------------------------- /chapter15/async_sync_change/main_asgiref_sync_to_async.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from fastapi import FastAPI,Request 4 | 5 | from fastapi.responses import PlainTextResponse,HTMLResponse 6 | from asgiref.sync import sync_to_async 7 | import requests 8 | # 定义我们的APP服务对象 9 | app = FastAPI() 10 | 11 | def getdata(): 12 | return requests.get('http://www.baidu.com').text 13 | 14 | 15 | 16 | 17 | @app.get("/get/access_token") 18 | async def access_token(): 19 | asds= await sync_to_async(func=getdata)() 20 | return HTMLResponse(asds) 21 | 22 | 23 | if __name__ == "__main__": 24 | import uvicorn 25 | import os 26 | 27 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 28 | print(app_modeel_name) 29 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 30 | 31 | 32 | -------------------------------------------------------------------------------- /chapter15/async_sync_change/main_asyncer_asyncify.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI,Request 2 | from fastapi.responses import PlainTextResponse,HTMLResponse 3 | from asyncer import asyncify 4 | import requests 5 | # 定义我们的APP服务对象 6 | app = FastAPI() 7 | 8 | def do_sync_work(name): 9 | return requests.get(f'http://www.baidu.com?name={name}').text 10 | 11 | @app.get("/get/access_token") 12 | async def access_token(request:Request): 13 | message = await asyncify(do_sync_work)(name="World") 14 | return HTMLResponse(message) 15 | 16 | 17 | if __name__ == '__main__': 18 | import uvicorn 19 | uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) 20 | -------------------------------------------------------------------------------- /chapter15/async_sync_change/main_asyncer_syncify.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI,Request 2 | from fastapi.responses import PlainTextResponse 3 | from fastapi.params import Body 4 | from fastapi.background import BackgroundTasks 5 | from asyncer import asyncify,syncify 6 | 7 | app = FastAPI() 8 | 9 | @app.post("/get/access_token") 10 | def access_token(request:Request,name=Body(...)): 11 | body = syncify(request.body)() 12 | print(body) 13 | return PlainTextResponse(body.decode(encoding='utf-8')) 14 | 15 | if __name__ == '__main__': 16 | import uvicorn 17 | uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) 18 | 19 | -------------------------------------------------------------------------------- /chapter15/async_wrapper/.runtest.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/async_wrapper/.runtest.prof -------------------------------------------------------------------------------- /chapter15/cProfile/c_profile_text_run.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def randomlist(n): 5 | lists = [] 6 | l = [random.random() for i in range(n)] 7 | l.sort() 8 | for v in l: 9 | lists.append(v) 10 | return lists 11 | 12 | 13 | 14 | 15 | if __name__ == "__main__": 16 | randomlist(20) -------------------------------------------------------------------------------- /chapter15/cProfile/crpresutl.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/cProfile/crpresutl.svg -------------------------------------------------------------------------------- /chapter15/cProfile/runtest.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/cProfile/runtest.prof -------------------------------------------------------------------------------- /chapter15/cProfile/runtest_profile.stats: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/cProfile/runtest_profile.stats -------------------------------------------------------------------------------- /chapter15/cProfile/runtest_profile_stats_run.py: -------------------------------------------------------------------------------- 1 | import pstats 2 | p = pstats.Stats("runtest_profile.stats") 3 | p.sort_stats("cumulative") # 和显示明细一样 4 | # p.print_stats() 5 | p.print_callers() # 可以显示函数被哪些函数调用 6 | -------------------------------------------------------------------------------- /chapter15/contextvar_request/bind_.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() -------------------------------------------------------------------------------- /chapter15/contextvar_request/main_class.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | from fastapi.responses import JSONResponse 6 | 7 | from chapter15.contextvar_request.request import request_var, request 8 | 9 | app = FastAPI() 10 | 11 | 12 | @app.middleware("http") 13 | async def add_process_time_header(request: Request, call_next): 14 | token = request_var.set(request) 15 | try: 16 | response = await call_next(request) 17 | return response 18 | finally: 19 | request_var.reset(token) 20 | 21 | 22 | 23 | 24 | @app.post('/index') 25 | async def index(): 26 | # 这里应该使用事务处理 27 | print(request.headers) 28 | return JSONResponse({ 29 | "code": 200, 30 | "msg": "成功" 31 | }) 32 | 33 | if __name__ == "__main__": 34 | import uvicorn 35 | import os 36 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 37 | print(app_modeel_name) 38 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 39 | -------------------------------------------------------------------------------- /chapter15/contextvar_request/request.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | from fastapi import Request 3 | from chapter15.contextvar_request.bind_ import bind_contextvar 4 | 5 | request_var: ContextVar[Request] = ContextVar("request") 6 | request:Request = bind_contextvar(request_var) -------------------------------------------------------------------------------- /chapter15/depends/main_class.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | 6 | app = FastAPI() 7 | 8 | 9 | class AuthCheck: 10 | def __init__(self, role: str): 11 | self.role = role 12 | 13 | @app.get("/auth_check") 14 | def auth_check(role: dict = Depends(AuthCheck)): 15 | return role 16 | 17 | if __name__ == "__main__": 18 | import uvicorn 19 | import os 20 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 21 | print(app_modeel_name) 22 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 23 | -------------------------------------------------------------------------------- /chapter15/depends/main_class_call.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | 6 | app = FastAPI() 7 | 8 | 9 | class AuthCheck: 10 | def __init__(self, role_name: str): 11 | self.role_name = role_name 12 | 13 | def __call__(self,): 14 | print("当前角色是:",self.role_name) 15 | if self.role_name =='admin': 16 | return "管理员" 17 | return "普通用户" 18 | 19 | @app.get("/auth_check") 20 | def auth_check(role: str = Depends(AuthCheck(role_name="admin"))): 21 | return role 22 | 23 | if __name__ == "__main__": 24 | import uvicorn 25 | import os 26 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 27 | print(app_modeel_name) 28 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 29 | -------------------------------------------------------------------------------- /chapter15/depends/main_class_security_scopes.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.security import SecurityScopes 3 | from fastapi import Security 4 | 5 | app = FastAPI() 6 | 7 | 8 | class AuthCheck: 9 | def __init__(self, security_scopes: SecurityScopes, role: str): 10 | print("传入的参数:", security_scopes.scopes) 11 | self.role = role 12 | 13 | 14 | @app.get("/auth_check2") 15 | def auth_check(role: str = Security(AuthCheck, scopes=["admin"])): 16 | return role 17 | 18 | 19 | if __name__ == "__main__": 20 | import uvicorn 21 | import os 22 | 23 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 24 | print(app_modeel_name) 25 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 26 | -------------------------------------------------------------------------------- /chapter15/depends/main_fun.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | 6 | app = FastAPI() 7 | 8 | 9 | def auth_check(role:str): 10 | return role 11 | 12 | @app.get("/auth_check") 13 | def auth_check(role: str = Depends(auth_check)): 14 | return role 15 | if __name__ == "__main__": 16 | import uvicorn 17 | import os 18 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 19 | print(app_modeel_name) 20 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 21 | -------------------------------------------------------------------------------- /chapter15/depends/main_fun_security_scopes.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.security import SecurityScopes 3 | from fastapi import Security 4 | 5 | app = FastAPI() 6 | 7 | 8 | def auth_check(security_scopes: SecurityScopes): 9 | print("传入的参数:", security_scopes.scopes) 10 | if security_scopes.scopes[0] == 'admin': 11 | return "管理者" 12 | return "普通用户" 13 | 14 | 15 | @app.get("/auth_check") 16 | def auth_check(role: str = Security(auth_check, scopes=["admin"])): 17 | return role 18 | 19 | 20 | if __name__ == "__main__": 21 | import uvicorn 22 | import os 23 | 24 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 25 | print(app_modeel_name) 26 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 27 | -------------------------------------------------------------------------------- /chapter15/fastapi_cache/uu.py: -------------------------------------------------------------------------------- 1 | x=3 2 | 3 | print(x) 4 | y=2 5 | k=x+y 6 | print(k) 7 | x=5 8 | y=7 9 | print(x*y) 10 | 11 | def jiafa(x,y): 12 | return x+ y 13 | 14 | print(jiafa(2,4)) 15 | 16 | 17 | print(jiafa(2,4333)) 18 | -------------------------------------------------------------------------------- /chapter15/model_sort/main_asyncer_syncify.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | app = FastAPI() 4 | 5 | from pydantic import BaseModel 6 | from typing import Optional 7 | 8 | 9 | class Item(BaseModel): 10 | 11 | def __new__(cls, *args, **kwargs): 12 | instance = super().__new__(cls) 13 | # 对当前__fields__重新进行排序 14 | cls.__fields__ = {key: cls.__fields__[key] for key in sorted(cls.__fields__.keys())} 15 | return instance 16 | 17 | desc: Optional[str] = None 18 | price: str 19 | age: str 20 | aname: str 21 | 22 | 23 | @app.post('/items/', response_model=Item) 24 | async def getitem(item: Item): 25 | return item 26 | 27 | 28 | if __name__ == "__main__": 29 | import uvicorn 30 | import os 31 | 32 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 33 | print(app_modeel_name) 34 | uvicorn.run(f"{app_modeel_name}:app", reload=True) 35 | -------------------------------------------------------------------------------- /chapter15/sentry/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/sentry/__init__.py -------------------------------------------------------------------------------- /chapter15/sentry/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | import sentry_sdk 4 | 5 | from sentry_sdk.integrations.asgi import SentryAsgiMiddleware 6 | 7 | sentry_sdk.init( 8 | dsn="http://8360febb6aae46deafde65afd092e481@192.168.126.130:9000/2", 9 | # Set traces_sample_rate to 1.0 to capture 100% 10 | # of transactions for performance monitoring. 11 | # We recommend adjusting this value in production, 12 | traces_sample_rate=1.0, 13 | ) 14 | 15 | app = FastAPI() 16 | 17 | @app.get("/sentry-debug") 18 | async def trigger_error(): 19 | division_by_zero = 1 / 0 20 | 21 | 22 | if __name__ == "__main__": 23 | import uvicorn 24 | import os 25 | 26 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 27 | print(app_modeel_name) 28 | uvicorn.run(f"{app_modeel_name}:app", reload=True) -------------------------------------------------------------------------------- /chapter15/smtplib/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter15/smtplib/test.jpg -------------------------------------------------------------------------------- /chapter15/smtplib/test1.txt: -------------------------------------------------------------------------------- 1 | 我是测试文件的内容! -------------------------------------------------------------------------------- /chapter15/smtplib/test2.txt: -------------------------------------------------------------------------------- 1 | 我是测试文件的内容! -------------------------------------------------------------------------------- /chapter16/async_sync_change/main_asgiref_async_to_sync.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from fastapi import FastAPI,Request 4 | from fastapi.responses import PlainTextResponse 5 | from fastapi.params import Body 6 | 7 | 8 | app = FastAPI() 9 | 10 | 11 | @app.post("/get/access_token") 12 | def access_token(request:Request,name=Body(...)): 13 | # print(reques.body()) 14 | from asgiref.sync import async_to_sync 15 | body = async_to_sync(request.body)() 16 | print(body) 17 | return PlainTextResponse(body.decode(encoding='utf-8')) 18 | 19 | 20 | if __name__ == '__main__': 21 | import uvicorn 22 | uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) -------------------------------------------------------------------------------- /chapter16/async_sync_change/main_asgiref_sync_to_async.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from fastapi import FastAPI,Request 4 | 5 | from fastapi.responses import PlainTextResponse,HTMLResponse 6 | from asgiref.sync import sync_to_async 7 | import requests 8 | # 定义我们的APP服务对象 9 | app = FastAPI() 10 | 11 | def getdata(): 12 | return requests.get('http://www.baidu.com').text 13 | 14 | 15 | 16 | 17 | @app.get("/get/access_token") 18 | async def access_token(): 19 | asds= await sync_to_async(func=getdata)() 20 | return HTMLResponse(asds) 21 | 22 | 23 | if __name__ == "__main__": 24 | import uvicorn 25 | import os 26 | 27 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 28 | print(app_modeel_name) 29 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 30 | 31 | 32 | -------------------------------------------------------------------------------- /chapter16/async_sync_change/main_asyncer_asyncify.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI,Request 2 | from fastapi.responses import PlainTextResponse,HTMLResponse 3 | from asyncer import asyncify 4 | import requests 5 | # 定义我们的APP服务对象 6 | app = FastAPI() 7 | 8 | def do_sync_work(name): 9 | return requests.get(f'http://www.baidu.com?name={name}').text 10 | 11 | @app.get("/get/access_token") 12 | async def access_token(request:Request): 13 | message = await asyncify(do_sync_work)(name="World") 14 | return HTMLResponse(message) 15 | 16 | 17 | if __name__ == '__main__': 18 | import uvicorn 19 | uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) 20 | -------------------------------------------------------------------------------- /chapter16/async_sync_change/main_asyncer_syncify.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI,Request 2 | from fastapi.responses import PlainTextResponse 3 | from fastapi.params import Body 4 | from fastapi.background import BackgroundTasks 5 | from asyncer import asyncify,syncify 6 | 7 | app = FastAPI() 8 | 9 | @app.post("/get/access_token") 10 | def access_token(request:Request,name=Body(...)): 11 | body = syncify(request.body)() 12 | print(body) 13 | return PlainTextResponse(body.decode(encoding='utf-8')) 14 | 15 | if __name__ == '__main__': 16 | import uvicorn 17 | uvicorn.run('main:app', host="127.0.0.1", port=8100, debug=True, reload=True) 18 | 19 | -------------------------------------------------------------------------------- /chapter16/async_wrapper/.runtest.prof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter16/async_wrapper/.runtest.prof -------------------------------------------------------------------------------- /chapter16/contextvar_request/bind_.py: -------------------------------------------------------------------------------- 1 | def bind_contextvar(contextvar): 2 | class ContextVarBind: 3 | __slots__ = () 4 | 5 | def __getattr__(self, name): 6 | return getattr(contextvar.get(), name) 7 | 8 | def __setattr__(self, name, value): 9 | setattr(contextvar.get(), name, value) 10 | 11 | def __delattr__(self, name): 12 | delattr(contextvar.get(), name) 13 | 14 | def __getitem__(self, index): 15 | return contextvar.get()[index] 16 | 17 | def __setitem__(self, index, value): 18 | contextvar.get()[index] = value 19 | 20 | def __delitem__(self, index): 21 | del contextvar.get()[index] 22 | 23 | return ContextVarBind() -------------------------------------------------------------------------------- /chapter16/contextvar_request/main_class.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | from fastapi.responses import JSONResponse 6 | 7 | from chapter15.contextvar_request.request import request_var, request 8 | 9 | app = FastAPI() 10 | 11 | 12 | @app.middleware("http") 13 | async def add_process_time_header(request: Request, call_next): 14 | token = request_var.set(request) 15 | try: 16 | response = await call_next(request) 17 | return response 18 | finally: 19 | request_var.reset(token) 20 | 21 | 22 | 23 | 24 | @app.post('/index') 25 | async def index(): 26 | # 这里应该使用事务处理 27 | print(request.headers) 28 | return JSONResponse({ 29 | "code": 200, 30 | "msg": "成功" 31 | }) 32 | 33 | if __name__ == "__main__": 34 | import uvicorn 35 | import os 36 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 37 | print(app_modeel_name) 38 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 39 | -------------------------------------------------------------------------------- /chapter16/contextvar_request/request.py: -------------------------------------------------------------------------------- 1 | from contextvars import ContextVar 2 | from fastapi import Request 3 | from chapter15.contextvar_request.bind_ import bind_contextvar 4 | 5 | request_var: ContextVar[Request] = ContextVar("request") 6 | request:Request = bind_contextvar(request_var) -------------------------------------------------------------------------------- /chapter16/depends/main_class.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | 6 | app = FastAPI() 7 | 8 | 9 | class AuthCheck: 10 | def __init__(self, role: str): 11 | self.role = role 12 | 13 | @app.get("/auth_check") 14 | def auth_check(role: dict = Depends(AuthCheck)): 15 | return role 16 | 17 | if __name__ == "__main__": 18 | import uvicorn 19 | import os 20 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 21 | print(app_modeel_name) 22 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 23 | -------------------------------------------------------------------------------- /chapter16/depends/main_class_call.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | 6 | app = FastAPI() 7 | 8 | 9 | class AuthCheck: 10 | def __init__(self, role_name: str): 11 | self.role_name = role_name 12 | 13 | def __call__(self,): 14 | print("当前角色是:",self.role_name) 15 | if self.role_name =='admin': 16 | return "管理员" 17 | return "普通用户" 18 | 19 | @app.get("/auth_check") 20 | def auth_check(role: str = Depends(AuthCheck(role_name="admin"))): 21 | return role 22 | 23 | if __name__ == "__main__": 24 | import uvicorn 25 | import os 26 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 27 | print(app_modeel_name) 28 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 29 | -------------------------------------------------------------------------------- /chapter16/depends/main_class_security_scopes.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.security import SecurityScopes 3 | from fastapi import Security 4 | 5 | app = FastAPI() 6 | 7 | 8 | class AuthCheck: 9 | def __init__(self, security_scopes: SecurityScopes, role: str): 10 | print("传入的参数:", security_scopes.scopes) 11 | self.role = role 12 | 13 | 14 | @app.get("/auth_check2") 15 | def auth_check(role: str = Security(AuthCheck, scopes=["admin"])): 16 | return role 17 | 18 | 19 | if __name__ == "__main__": 20 | import uvicorn 21 | import os 22 | 23 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 24 | print(app_modeel_name) 25 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 26 | -------------------------------------------------------------------------------- /chapter16/depends/main_fun.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from starlette.middleware.base import BaseHTTPMiddleware 4 | from fastapi import FastAPI, Request, Depends 5 | 6 | app = FastAPI() 7 | 8 | 9 | def auth_check(role:str): 10 | return role 11 | 12 | @app.get("/auth_check") 13 | def auth_check(role: str = Depends(auth_check)): 14 | return role 15 | if __name__ == "__main__": 16 | import uvicorn 17 | import os 18 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 19 | print(app_modeel_name) 20 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 21 | -------------------------------------------------------------------------------- /chapter16/depends/main_fun_security_scopes.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.security import SecurityScopes 3 | from fastapi import Security 4 | 5 | app = FastAPI() 6 | 7 | 8 | def auth_check(security_scopes: SecurityScopes): 9 | print("传入的参数:", security_scopes.scopes) 10 | if security_scopes.scopes[0] == 'admin': 11 | return "管理者" 12 | return "普通用户" 13 | 14 | 15 | @app.get("/auth_check") 16 | def auth_check(role: str = Security(auth_check, scopes=["admin"])): 17 | return role 18 | 19 | 20 | if __name__ == "__main__": 21 | import uvicorn 22 | import os 23 | 24 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 25 | print(app_modeel_name) 26 | uvicorn.run(f"{app_modeel_name}:app", host='127.0.0.1', reload=True) 27 | -------------------------------------------------------------------------------- /chapter16/model_sort/main_asyncer_syncify.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | app = FastAPI() 4 | 5 | from pydantic import BaseModel 6 | from typing import Optional 7 | 8 | 9 | class Item(BaseModel): 10 | 11 | def __new__(cls, *args, **kwargs): 12 | instance = super().__new__(cls) 13 | # 对当前__fields__重新进行排序 14 | cls.__fields__ = {key: cls.__fields__[key] for key in sorted(cls.__fields__.keys())} 15 | return instance 16 | 17 | desc: Optional[str] = None 18 | price: str 19 | age: str 20 | aname: str 21 | 22 | 23 | @app.post('/items/', response_model=Item) 24 | async def getitem(item: Item): 25 | return item 26 | 27 | 28 | if __name__ == "__main__": 29 | import uvicorn 30 | import os 31 | 32 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 33 | print(app_modeel_name) 34 | uvicorn.run(f"{app_modeel_name}:app", reload=True) 35 | -------------------------------------------------------------------------------- /chapter16/sentry/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter16/sentry/__init__.py -------------------------------------------------------------------------------- /chapter16/sentry/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | import sentry_sdk 4 | 5 | from sentry_sdk.integrations.asgi import SentryAsgiMiddleware 6 | 7 | sentry_sdk.init( 8 | dsn="http://8360febb6aae46deafde65afd092e481@192.168.126.130:9000/2", 9 | # Set traces_sample_rate to 1.0 to capture 100% 10 | # of transactions for performance monitoring. 11 | # We recommend adjusting this value in production, 12 | traces_sample_rate=1.0, 13 | ) 14 | 15 | app = FastAPI() 16 | 17 | @app.get("/sentry-debug") 18 | async def trigger_error(): 19 | division_by_zero = 1 / 0 20 | 21 | 22 | if __name__ == "__main__": 23 | import uvicorn 24 | import os 25 | 26 | app_modeel_name = os.path.basename(__file__).replace(".py", "") 27 | print(app_modeel_name) 28 | uvicorn.run(f"{app_modeel_name}:app", reload=True) -------------------------------------------------------------------------------- /chapter16/smtplib/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gitxieada/fastapi_tutorial/a80a79cf4440669e721b124beb07dbbea2338147/chapter16/smtplib/test.jpg -------------------------------------------------------------------------------- /chapter16/smtplib/test1.txt: -------------------------------------------------------------------------------- 1 | 我是测试文件的内容! -------------------------------------------------------------------------------- /chapter16/smtplib/test2.txt: -------------------------------------------------------------------------------- 1 | 我是测试文件的内容! --------------------------------------------------------------------------------