Fastapi template generation, database version management tools
fastapi+sqlalchemy
This project includes template directory (./templates) and template application tool (/ serializer.py )It provides a tool for developers to customize and modify
Templates : holds the template file. Support developers to modify custom models
serializer.py : Responsible for writing template files to main.py To be a variable. Support developers to modify or develop new templates
conf.py : Contains configurable template parameters
main.py : Responsible for providing all functions, creating projects, performing migrations, etc
pip install fastapi-manage
Create a fastapi project in the current directory, the directory name is the project name currently entered
fastapi-manage startproject yourproject
Create a migration for the project
cd ./yourproject
python manage.py makemigrations
Apply the migration to the database
cd ./yourproject
python mangage.py migrate
Start a web service
cd ./yourproject
python manage.py runserver
shell fastapi-manage --help
# View the help of fastapi-manage command
Options:
-h, --host [default:127.0.0.1]
-p, --port [default:8000]
-w, --workers [default:1]
--reload auto-reloader
cd ./yourproject
Most of the configuration items are in the core/config.py file, such as: database configuration, token expiration time, cross-domain configuration and so on.
Middleware, log related, root routing can be configured in main.py
The models of the database are stored in the models folder, and there are two classes that can be used, namely Base and User Base
There are two classes in the base class file, User Base and Base
Compared with Base, User Base only adds a _groups field to cooperate with the grouping function of the authentication middleware.
Base class has id, create_at, update_at, deleted by default. If you do not specify __tablename__ when writing the class, Base will automatically specify the table name of the modified model in lowercase format of the current class name. Base will specify the InnoDB engine by default. These configurations are placed directly in dbbase_class.py, if you are not satisfied with these settings at any time, you can modify them directly without restriction
This folder is a file used to identify all models for alembic. In fact, this folder is a bit tasteless.
Models in models can inherit Base or UserBase, which can simplify development, but there is one thing to note: After writing the class, please import it into models__init__.py. There is a User sample class in the generated project, which can be used as a reference, and User can be deleted directly if it is not needed.
Here you can see how the sessions of redis and sqlalchemy are obtained. You can adjust the sqlalchemy thread pool (pool size) by default to 8.
The compilation of the interface is placed in the apiendpoints folder, which can be divided according to personal needs. There is a user.py file in the example
Only some commonly used packages are imported in user.py, and router objects are defined.
Example:
@router.get("/", summary='get_all_user')
async def get_all_user(*, utils: UtilsObject = Depends(Utils(False)),) -> Any:
user = ["A", "B", "C"]
return user
- query process:
The session can be obtained through utils.db.session, and the life cycle of the session will be automatically managed, and the session will be automatically returned at the end of the interface call.
@router.get("/", summary='get_all_user')
def get_all_user(*, utils: UtilsObject = Depends(Utils(False)),) -> Any:
session = utils.db.session # type: sqlalchemy.orm.Session
users = session.query(models.User).filter_by(username="hello").all() # query
return users
After getting the session, you can do anything that sqlalchemy did before.
Utils(False) declares that the interface does not need to be authenticated. If authentication is required, just change it to True, and you can specify the allowed group (List[str]). After specifying the group, the ones that are not in the group The user will also be denied access.
- Authentication:
You can log in as long as the authentication is successful (the token is verified and has not expired)
Before setting Utils to True (before enabling authentication), you need to implement the login interface and register the API LOGIN URL in config.py
@router.get("/", summary='get_all_user')
def get_all_user(*, utils: UtilsObject = Depends(Utils(True)),) -> Any:
return "hello"
Need to be authenticated successfully, and the group in jwt is in the specified scopes
@router.get("/", summary='get_all_user')
def get_all_user(*, utils: UtilsObject = Depends(Utils(True, ['admin', 'superadmin'])),) -> Any:
return "hello"
The utils object can be understood as a Request object, but utils has an additional db object, which is a superset of request.
-
get jwt
Generally used when the user logs in, to create an identity for the user (jwt)
@router.get("/login", summary="login") def login(*, utils: UtilsObject = Depends(Utils(False)),) -> Any: user_id = "12345678" # Unique label: int jwt = create_access_token(user_id, ["admin"]) return jwt """ access_token: str token_type: str """
-
password hash & verify_password
from libs.security import get_password_hash, verify_password hashed_password = get_password_hash("my_password") result: bool = verify_password("my_password", hashed_password)
get_password_hash -> Generally used when adding users, hash the user password and put it in the database
verify_password -> Generally used when logging in to verify whether the user password is consistent with the hashed password in the database
-
Paging plugin pagination
The performance of this plugin in executing count is not very good.
引入Pagination依赖后,会自动增加两个查询参数: page, page_size 代表页数和每页的数量,当page_size 超过max_page_size后,将会引发status_code=400异常. After the Pagination dependency is introduced, two query parameters will be automatically added: page, page_size represent the number of pages and the number of each page, when page_size exceeds max_page_size, status_code=400 exception will be raised.
The default maximum number per page is 400
@router.get("/", summary='get_all_user') def get_all_user(*, utils: UtilsObject = Depends(Utils(True, ['admin', 'superadmin'])), pagination: Pagination = Depends()) -> Any: session = utils.db.session pagination.queryset = session.query(models.User).filter_by(is_active=True) return pagination.get_page()
If you need to modify the maximum number of each page, you can do this:
@router.get("/", summary='get_all_user') def get_all_user(*, utils: UtilsObject = Depends(Utils(True, ['admin', 'superadmin'])), pagination: Pagination = Depends(Pagination(5000))) -> Any: session = utils.db.session pagination.queryset = session.query(models.User).filter_by(is_active=True) return pagination.get_page()
-
middleware
-
authentication Authentication middleware is added by default. After adding this middleware, Utils() will be able to control whether the user needs authentication. It is also possible not to add it, but if Utils(True) will throw an exception to remind that there is no middleware available
-
auto_db_session It will be used to provide the db object in utils. It is responsible for creating and acquiring session where the session is needed, and returning the session at the end of the interface call. It is a middleware that automatically manages sessoin.
The performance of this middleware is not good, because the performance of Starlette's Base HTTP Middleware is not very good, and auto db session inherits this class. Every time a subclass of Base HTTP Middleware is added to the local test, there will be a larger concurrency. Decline, plan to improve.
-
rate_limit The current limiting middleware is used to limit the access speed of each user and integrates asgi-ratelimit. For specific use, please refer to https:pypi.orgprojectasgi-ratelimit
-
-
libs
- dependencies The utils object is implemented, and the logic of utils is here
- pagination Paging tool encapsulates a paging tool.
- security Security class, which implements the methods of jwt generation, password hashing, and password verification
This folder can be understood as django's serializer (serializers.py),After adding the serializer, it is recommended to import this class into schemes__init__.py, which can simplify the subsequent import
Used to store all serializer objects
The specific usage is the same as the official documents
Used to place some asynchronous tasks, encapsulated by celery, the usage is basically the same as celery, but the file path is customized. The related back-end configuration is also in config.
testFolder
start-celery.py
start-gunicorn Start the live process, use gunicorn to guard
- Sqlalchemy has released version 1.4, which provides asynchronous support. original idea was to be able to identify whether it is an asynchronous drive library through the SQLALCHEMY DATABASE URI variable in config.py to identify whether it is an asynchronous drive library to switch between synchronous session and asynchronous sessino, but After doing this, the auto-completion will be messed up, and there is no better idea.
- auto_db_session The current performance is not ideal, and it needs to be separated from the Base HTTP Middleware dependency, which has not been implemented yet. .
- Fork the repository
- Create Feat_xxx branch
- Commit your code
- Create Pull Request