Tortoise ORM / FastAPI Integration Quick Notes

Original link: https://editor.leonh.space/2022/tortoise/

Because I have been spoiled by Active Record in the past, I have not been able to find the same ORM in the Python circle, and because I am not using a spree framework like Django, I have always been looking for ORMs on the road, and today I am again and again. We are going to introduce another Tortoise ORM again.

Blow a wave of characteristics first:

  • Supports SQLite, PostgreSQL, MariaDB, MySQL, and supports SQL Server, Oracle through ODBC.
  • asynchronous.
  • There is a migration mechanism.
  • Supports integration of multiple packages and frameworks, including UnitTest, FastAPI, Quart, Sanic, Starlette, aiohttp, BlackSheep, Pydantic , some of the above are popular and unpopular, but the strange thing is that there is no Flask. Even if it is not in the above list, as long as you understand the initialization mechanism of Tortoise, you can integrate it yourself.
  • Supports multiple databases.
  • Support read-write separation.
  • But there is no seeding mechanism, it is self-drying.

Below is a quick note on Tortoise and FastAPI/pydantic integration.

Define Model

The model here refers to the ORM model, and the pydantic model is derived from the ORM model, such as the following models.py:

 from tortoise import fields, models from tortoise.contrib.pydantic import pydantic_model_creator  class Word ( models.Model ):    id = fields. IntField ( pk = True )    #: `word` may duplicate, do not have to be unique. word = fields. CharField ( max_length = 255 , null = False ) accent_notation = fields. CharField ( max_length = 255 , null = False )         class Meta : table = ' words ' # Always name with snake_case  WordRead = pydantic_model_creator (    cls =Word,    name =' WordRead ' )  WordCreate = pydantic_model_creator (    cls =Word,    name =' WordCreate ',    exclude_readonly = True # Exclude `id` on creating )

Here we define a Word model, and its fields are defined by the fields series functions, which should be literate.

In addition to the field definitions, there are some declarations worth mentioning:

  • There is a line of comments starting with #: on the word . The comments in this format will become the field description of pydantic, and therefore will also become the property description of OpenAPI.
  • The table attribute of the subclass Meta declares the name of the data table of the model, because individuals are used to using snake case in the data table, so this item must be additionally declared.

With the ORM model, we will use pydantic_model_creator() to create two derived pydantic models. It is customary for their variable names and model names to be the same.

Finally, this models.py has three members:

  • A Word ORM model.
  • A WordRead pydantic model
  • A WordCreate pydantic model without an id field because the ID is automatically generated by the database and does not need to be provided by the user.

Later we will use them in FastAPI endpoint functions.

Tortoise ORM integrates FastAPI

Tortoise provides a fool integration mechanism, which automatically brings up Tortoise when FastAPI starts, and closes the connection between Tortoise and the database when it ends.

In the FastAPI main program main.py like this:

 from fastapi import FastAPI from tortoise.contrib.fastapi import register_tortoise from app.models import WordCreate, Word, WordRead  app: FastAPI = FastAPI ()  register_tortoise (    app =app,    db_url =' sqlite://db.sqlite ',    modules ={' models ': [' app.models ']},    generate_schemas = True ,    add_exception_handlers = True , )

The sentence register_tortoise() can be done in one line, it fools you and is smart.

Call Tortoise Model in FastAPI

Of the three models defined above, the Word model is used to operate the database, and the other two models are used to declare parameters or return value types in FastAPI functions, such as the following function:

 @app. post (    path =" / ",    response_model =WordRead, ) async def create_word (    word : WordCreate, ): new_word: WordRead = await Word. create ( **word. dict (            exclude_unset = True , ) )    return new_word

WordRead is declared as the return type, WordCreate is declared as the parameter word type, and the actual database statement is composed of Word.create() , and the conversion between them is handled by Tortoise ORM.

Here is another example of CRUD:

 @app. get (    path =' / {word} ',    response_model =WordRead, ) async def get_word (    word : str ): response: WordRead = await Word. get (        word =word )    return response

By analogy with the previous example, WordRead is also declared as a return type, and the actual operation database is through Word.get() .

Epilogue

This article is a quick note of Tortoise ORM in FastAPI. It does not mention some important features, such as various fancy field definitions, associations, quary API, etc., maybe I will write it later, please.

This article is reprinted from: https://editor.leonh.space/2022/tortoise/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment