|
| 1 | +================= |
| 2 | +Models and fields |
| 3 | +================= |
| 4 | +To get working with models, first you should import them |
| 5 | + from tortoise.models import Model |
| 6 | + |
| 7 | +With that you can start describing your own models like that |
| 8 | + |
| 9 | +.. code-block:: python |
| 10 | +
|
| 11 | + class Tournament(Model): |
| 12 | + id = fields.IntField(pk=True) |
| 13 | + name = fields.StringField() |
| 14 | + created = fields.DatetimeField(auto_now_add=True) |
| 15 | +
|
| 16 | + def __str__(self): |
| 17 | + return self.name |
| 18 | +
|
| 19 | +
|
| 20 | + class Event(Model): |
| 21 | + id = fields.IntField(pk=True) |
| 22 | + name = fields.StringField() |
| 23 | + tournament = fields.ForeignKeyField('models.Tournament', related_name='events') |
| 24 | + participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team') |
| 25 | + modified = fields.DatetimeField(auto_now=True) |
| 26 | + prize = fields.DecimalField(max_digits=10, decimal_places=2, null=True) |
| 27 | +
|
| 28 | + def __str__(self): |
| 29 | + return self.name |
| 30 | +
|
| 31 | +
|
| 32 | + class Team(Model): |
| 33 | + id = fields.IntField(pk=True) |
| 34 | + name = fields.StringField() |
| 35 | +
|
| 36 | + def __str__(self): |
| 37 | + return self.name |
| 38 | +
|
| 39 | +Let see in details what we accomplished here: |
| 40 | + |
| 41 | +.. code-block:: python |
| 42 | +
|
| 43 | + class Tournament(Model): |
| 44 | +
|
| 45 | +Every model should be derived from base model. You also can derive from your own model subclasses and you can make abstract models like this |
| 46 | + |
| 47 | +.. code-block:: python |
| 48 | +
|
| 49 | + class AbstractTournament(Model): |
| 50 | + id = fields.IntField(pk=True) |
| 51 | + name = fields.StringField() |
| 52 | + created = fields.DatetimeField(auto_now_add=True) |
| 53 | +
|
| 54 | + class Meta: |
| 55 | + abstract = True |
| 56 | +
|
| 57 | + def __str__(self): |
| 58 | + return self.name |
| 59 | +
|
| 60 | +This models won't be created in schema generation and won't create relations to other models. |
| 61 | + |
| 62 | +Further, let's take a look at created fields for models |
| 63 | + |
| 64 | +.. code-block:: python |
| 65 | +
|
| 66 | + id = fields.IntField(pk=True) |
| 67 | +
|
| 68 | +This code defines integer primary key for table. Sadly, currently only simple integer pk is supported. |
| 69 | + |
| 70 | +.. code-block:: python |
| 71 | +
|
| 72 | + tournament = fields.ForeignKeyField('models.Tournament', related_name='events') |
| 73 | + participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team') |
| 74 | + modified = fields.DatetimeField(auto_now=True) |
| 75 | + prize = fields.DecimalField(max_digits=10, decimal_places=2, null=True) |
| 76 | +
|
| 77 | +In event model we got some more fields, that could be interesting for us. |
| 78 | +``fields.ForeignKeyField('models.Tournament', related_name='events')`` - here we create foreign key reference to tournament. We create it by referring to model by it's literal, consisting of app name and model name. `models` is default app name, but you can change it in `class Meta` with `app = 'other'`. |
| 79 | +``related_name`` is keyword argument, that defines field for related query on referenced models, so with that you could fetch all tournaments's events with like this: |
| 80 | + |
| 81 | +.. code-block:: python |
| 82 | +
|
| 83 | + await tournament.events.all() |
| 84 | +
|
| 85 | +or like this: |
| 86 | + |
| 87 | +.. code-block:: python |
| 88 | +
|
| 89 | + await tournament.fetch_related('events') |
| 90 | +
|
| 91 | +
|
| 92 | +Next field is ``fields.ManyToManyField('models.Team', related_name='events', through='event_team')``. It describes many to many relation to model Team. |
| 93 | +Here we have additional kwarg ``through`` that defines name of intermediate table. |
| 94 | + |
| 95 | +Further we have field ``fields.DatetimeField(auto_now=True)``. Options ``auto_now`` and ``auto_now_add`` work like Django's options. |
| 96 | + |
| 97 | +Init app |
| 98 | +======== |
| 99 | + |
| 100 | +After you defined all your models, tortoise needs you to init them, in order to create backward relations between models and match your db client with appropriate models. |
| 101 | + |
| 102 | +You can do it like this: |
| 103 | + |
| 104 | +.. code-block:: python |
| 105 | +
|
| 106 | + from tortoise.backends.asyncpg.client import AsyncpgDBClient |
| 107 | + from tortoise import Tortoise |
| 108 | + from app import models # without importing models Tortoise can't find and init them |
| 109 | +
|
| 110 | +
|
| 111 | + async def init(): |
| 112 | + db = AsyncpgDBClient( |
| 113 | + host='localhost', |
| 114 | + port=5432, |
| 115 | + user='postgres', |
| 116 | + password='qwerty123', |
| 117 | + database='events', |
| 118 | + ) |
| 119 | + |
| 120 | + await db.create_connection() |
| 121 | + Tortoise.init(db) |
| 122 | + |
| 123 | + await generate_schema(client) |
| 124 | +
|
| 125 | +Here we create connection to database with default asyncpg client and then we init models. Be sure that you have your models imported in the app. Usually that's the case, because you use your models across you app, but if you have only local imports of it, tortoise won't be able to find them and init them with connection to db. |
| 126 | +``generate_schema`` generates schema on empty database, you shouldn't run it on every app init, run it just once, maybe out of your main code. |
| 127 | + |
| 128 | + |
| 129 | +Fields |
| 130 | +====== |
| 131 | + |
| 132 | +Here is list of fields available at the moment with custom options of this fields: |
| 133 | + |
| 134 | +- IntField (``pk``) |
| 135 | +- SmallIntField |
| 136 | +- StringField |
| 137 | +- BooleanField |
| 138 | +- DecimalField (``max_digits``, ``decimal_places``) |
| 139 | +- DatetimeField (``auto_now``, ``auto_now_add``) |
| 140 | +- DateField |
| 141 | +- ForeignKeyField (model_name, related_name, on_delete) |
| 142 | +- ManyToManyField (``model_name``, ``related_name``, ``through``, ``backward_key``, ``forward_key``) |
| 143 | + |
| 144 | +Also all fields fields have this options: |
| 145 | +- ``source_field`` - field name in schema, can be different from field name |
| 146 | +- ``null`` - is field nullable |
| 147 | +- ``default`` - default value for field |
| 148 | +- ``generated`` - flag that says that this field is read only and value should be generated in db. Normally, should be used only if you working on already created schema, not generated by tortoise. |
| 149 | + |
0 commit comments