コンテンツにスキップ

モデルメソッド

!!!tipデータベースとの主な相互作用は、django ormと同様に、各モデルでModel. objectとして公開されているQuerySetオブジェクトを介して公開されています。

1
についてもっと読む **クエリ、テーブルの結合、フィールドの除外など。 [クエリ][queries] セクション**

各モデルインスタンスには、それ自体を保存、更新、または読み込むための一連のメソッドがあります。

利用可能な方法は次のとおりです。

陳腐な方法

各ormar. Modelもpydantic.BaseModelであるため、すべてのpydanticメソッド、特にmodel_dump()メソッドとmodel_dump_json()メソッドもモデルで使用でき、除外、インクルード、その他のパラメーターも受け入れることができることに注意してください。

詳細については、pydanticドキュメントを参照してください

モデル()

Model_構築は、新しいインスタンスを構築するための__in it__メソッドの元の等価物です。

何が違うかというと、モデル_コンストラクトはバリデーションをスキップするので、データが正しく信頼できるとわかっているときに使うべきです。コンストラクトを使うメリットは、バリデーションをスキップすることで実行速度が上がることです。

!!!note pydantic. model_structureメソッドとは対照的に、ormar同等のメソッドはネストされた関連モデルも処理することに注意してください。

警告コンストラクタメソッドは、検証がスキップされるため、変換、チェックなどを実行しないことに注意してください。したがって、有効でデータベースで使用できるデータを提供するのはあなたの責任です。

1
2
3
4
構築がまだ実行する唯一の2つのことは次のとおりです。

*  未設定フィールドに対する `default` 値の提供
*  ディクショナリまたはプライマリキーの値を渡すと、ネストされたormarモデルを初期化します。

モデルダンプ()

model_dumpはpydanticからメソッドを継承していますが、ormarは独自の引数を追加したり、デフォルト値を使う際に若干のニュアンスがあるので、わかりやすいようにここに記載しています。

model_dumpは、その名の通り、モデルツリーからディクショナリにデータをエクスポートします。

model_dumpパラメーターの説明:

含める(または変更する)

include: Union[Set, Dict] = None

返されるディクショナリに含めるフィールド名セットまたはディクショナリ。

pydanticには、インデックスによってリスト内のフィールドを含む/除外するという珍しいパターンがあることに注意してください(ネストされたモデルも同様です)。すべてのサブアイテム内のフィールドを除外する場合は、__all__キーを辞書に渡す必要があります。

pydanticではSetsでネストされたモデルを除外することはできませんが、ormarでは可能です(リレーショナル名にダブルアンダースコアを追加することで、使用できる書籍のカテゴリ名を除外します)exclude={"book__category__name"})

ormarはインデックスの除外/包含をサポートしておらず、簡略化されたユーザーフレンドリーな表現を受け入れます。

ネストされたフィールドを含むフィールドを含める/除外する方法を確認するには、説明と多数の例を含むフィールドのセクションを参照してください。

!!!注実際、ormarでは、コレクション内のネストされたモデルを除外でき、fastapiのresponse_model_cludeとresponse_model_includeでモデルツリー全体から除外できます。

除外(または変更)

exclude: Union[Set, Dict] = None

返されるディクショナリから除外するフィールド名のコレクションまたはディクショナリ。

pydanticには、インデックスによってリスト内のフィールドを含む/除外するという珍しいパターンがあることに注意してください(ネストされたモデルも同様です)。すべてのサブアイテム内のフィールドを除外する場合は、__all__キーを辞書に渡す必要があります。

PydanticではSetsでネストされたモデルを除外することはできませんが、ormarでは(リレーショナル名に二重アンダースコアを追加することで、使用している書籍のカテゴリ名を除外します)exclude={"book__category__name"})

ormarはインデックスの除外/包含をサポートしておらず、簡略化されたユーザーフレンドリーな表現を受け入れます。

ネストされたフィールドを含むフィールドを含める/除外する方法を確認するには、説明と多数の例を含むフィールドのセクションを参照してください。

!!!注実際、ormarでは、コレクション内のネストされたモデルを除外でき、fastapiのresponse_model_cludeとresponse_model_includeでモデルツリー全体から除外できます。

除外_設定解除

未設定を除外:ブール=False

Flagは、モデルの作成時に明示的に設定されていないフィールドを、返されるディクショナリから除外するかどうかを示します。

!!!警告データをデータベースに保存すると、各フィールドには独自の値->があり、デフォルトまたはなしで指定できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
つまり、データベースからデータを読み込むと、**のすべての**フィールドが設定され、このフラグは基本的に機能しなくなります。


class Category(ormar. Model):
    or_config=base_or_config. copy(tablename="カテゴリ")

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100,default="Test")
    可視性: bool=ormar.Boolean(デフォルト=True)


class Item(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    price: float=ormar.Float(デフォルト=9.99)
    カテゴリー:リスト[カテゴリー]=ormar. ManyTomany(カテゴリー)

Category=Category(name="テスト2")
assert category. model_dump()=={'id':None,'items':[],'name':'Test 2',
                           '可視性': True}
assert category. model_dump(除外_未設定=True)== {'items': [], 'name': 'Test 2'}

Waitcategory.save()
Category 2=await Category. object.get()
assert category 2. model_dump()=={'id':1,'items':[],'name':'Test 2',
                            '可視性': True}
#DBから読み込んだ後、すべてのフィールドが明示的に設定される方法に注意してください。
#これは、dbからモデルを入力すると発生することです。
assert category 2. model_dump(除外_未設定=True)=={'id':1,'items':[],
                                              'name':'Test 2','visibility': True}

デフォルト値を除外

exclude_defaults: bool = False

フラグは、デフォルト値に等しいことを示します(設定されているかどうかに関係なく)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Category(ormar. Model):
    or_config=base_or_config. copy(tablename="カテゴリ")

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100,default="Test")
    可視性: bool=ormar.Boolean(デフォルト=True)

class Item(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    price: float=ormar.Float(デフォルト=9.99)
    カテゴリー:リスト[カテゴリー]=ormar. ManyTomany(カテゴリー)

カテゴリー=カテゴリー()
#整数pkはデフォルトでは自動インクリメントであるため、オプションであることに注意してください。
assert category. model_dump()== {'id': None, 'items': [], 'name': 'Test', 'visibility': True}
assert category. model_dump(除外_デフォルト=True)== {'items': []}

#データを保存してリロードする
Waitcategory.save()
Category 2=await Category. object.get()

assertカテゴリー2. model_dump()== {'id': 1, 'items': [], 'name': 'Test', 'visibility': True}
assert Category 2. model_dump(除外_デフォルト=True)== {'id': 1, 'items': []}

除外_なし

除外_なし:ブール=False

Flagは、返されたディクショナリからNoneに等しいフィールドを除外するかどうかを示します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Category(ormar. Model):
    or_config=base_or_config. copy(tablename="カテゴリ")

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100,default="Test",nullable=True)
    可視性: bool=ormar.Boolean(デフォルト=True)


class Item(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    price: float=ormar.Float(デフォルト=9.99)
    カテゴリー:リスト[カテゴリー]=ormar. ManyTomany(カテゴリー)


カテゴリー=カテゴリー(name=None)
assert category. model_dump()=={'id':None,'items':[],'name':None,
                           '可視性': True}
#note idはまだ設定されていないのでNoneと除外
assert category. model_dump(除外なし=True)== {'items': [], 'visibility': True}

Waitcategory.save()
Category 2=await Category. object.get()
assert category 2. model_dump()=={'id':1,'items':[],'name':None,
                            '可視性': True}
assert category 2. model_dump(除外_none=True)=={'id':1,'items':[],
                                             '可視性': True}

_main_keysを除く(ormarのみ)

exclude_primary_keys: bool = False

フラグをTrueに設定すると、ネストされたモデルを含むツリー内のすべてのプライマリキーカラムが除外されます。

1
2
3
4
5
6
7
8
9
class Item(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)

item 1=Item(id=1, name="テスト項目")
assert item 1. model_dump()== {"id": 1, "name": "Test Item"}
assert item 1. model_dump(除外_プライマリ_keys=True)== {"name": "Test Item"}

_through_modelを除く(ormarのみ)

exclude_through_models: bool = False

パススルーモデルは、多対多のリレーションシップごとに自動的に追加され、リンクされたモデル/テーブルに追加のパラメーターが保存されます。

out put_through_models=Trueを設定すると、サブモデルのパススルーモデルを含むすべてのパススルーモデルが除外されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Category(ormar. Model):
    or_config=base_or_config. copy(tablename="カテゴリ")

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)


class Item(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    カテゴリー:リスト[カテゴリー]=ormar. ManyTomany(カテゴリー)

#モデルを定義するツリー
アイテム辞書={
            "name":"test",
            "カテゴリー":[{"name": "test cat"},{"name": "test cat2"}],
        }
#ツリー全体を保存
await Item(**item_dict). save_関連(follow=True,save_all=True)

#保存した値を取得する
item=awaitアイテム。オブジェクト。選択関連("カテゴリ")。get()

#デフォルトでは、スルーモデル(アイテムカテゴリ)を見ることができます。
assert item. model_dump()=={'id':1,'name':'test',
                       'カテゴリー':[
                           {'id': 1,'name':'test cat',
                            'itemcategory':{'id': 1, 'category': None, 'item': None}},
                           {'id': 2,'name':'test cat 2',
                            'アイテムカテゴリー':{'id': 2, 'category': None, 'item': None}}
                       ]}

#これらのフィールド/モデルを除外できます
assert item. model_dump(除外_スルー_モデル=True)=={
                       'id': 1,'name':'test',
                       'カテゴリー':[
                           {'id': 1, 'name': 'test cat'}, 
                           {'id': 2, 'name': 'test cat2'}
                       ]}

model_dump_json()

model_dump_json()はmodel_dump()と全く同じ引数なので、上記を確認します。

もちろん、最終的な結果は辞書ではなくjsonで表される文字列です。

_pydantic()を取得する

get_pydantic(include: Union[Set, Dict] = None, exclude: Union[Set, Dict] = None)

このメソッドを使用すると、すべてのフィールドを再入力することなく、ormarモデルからpydanticモデルを生成できます。

ネストされたモデルがある場合、pydanticモデルツリー全体が生成されることに注意してください!しかし、ループ参照の問題を防ぐ方法で。

さらに、除外および/または包含パラメーターを渡して、ネストされたモデルに含めて、必要なフィールドのみを保持できます。

これは、fastapiでのリクエストとレスポンスのpydanticモデルを簡単に作成できることを意味します。

!!!(注)可能な除外/インクルード、および除外辞書または設定の構築方法の詳細については、ドキュメントのフィールドセクションを参照してください

与えられたサンプルormarモデルは以下の通りです:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
base_ormar_config=ormar. OrmarConfig(ベースの設定
    metadata=sqlalchemy. MetaData(),
    Database(DATABASE_URL, force_rollback=True),
)


class Category(ormar. Model):
    or_config=base_or_config. copy(tablename="カテゴリ")

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)


class Item(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100,default="test")
    カテゴリー:オプション[カテゴリー]=ormar. ForeignKey(カテゴリー、nullable=True)

簡単な呼び出しでpydanticモデルを生成できます。

1
PydanticCategory=Category. get_pydantic(include={"id", "name"})

これにより、次のようなモデルが生成されます。

1
2
3
class Category(BaseModel):
    id:オプション[int]
    name:オプション[str]="test"

!!!警告モジュール内に同じ名前のクラスを複数持つことは良い習慣ではなく、fastapiドキュメントを破壊する可能性があることに注意してください。そのため、ormarはクラス名にランダムに3つの大文字を追加します。 上記の例では、これは実際にクラスがCategory_XIP(BaseModel)という名前になることを意味します。

ネストされたフィールドを除外または含めるには、辞書またはアンダースコアを使用できます。

1
2
3
#両方の呼び出しは同等です
PydanticCategory=Category. get_pydantic(include={"id", "items__id"})
PydanticCategory=Category. get_pydantic(include={"id":.。。"items":{"id"}})

生成された構造は次のとおりです。

1
2
3
4
5
6
class Item(BaseModel):
    id:オプション[int]

class Category(BaseModel):
    id:オプション[int]
    item:オプション[リスト[アイテム]]

もちろん、深い入れ子構造を使用することもできます。これにより、ormarは(ループを除外する方法で)pydantic同等物を生成します。

ormarでは関係が双方向であるにもかかわらず、上記のItemモデルがCategoryへの参照を持たないことに注意してください(そしてormar. Itemにはカテゴリフィールドがあります)。

警告生成されたpydanticモデルは、ormar選択ベリファイアやpydantic. validatorデコレータを使用して定義されたベリファイアなど、すべてのフィールドベリファイアを元のormarモデルから継承することに注意してください。

1
しかし、同時に `ormar` モデル上に存在するすべてのルートバリデータは、**NOT**が生成されたpydanticモデルにコピーされます。

ルートバリデーターはすべてのフィールドで操作でき、ユーザーはPydanticモデルの生成中に一部のフィールドを除外できるため、これらのバリデーターをコピーすることは安全ではありません。 必要に応じて、生成されたpydanticモデルに再定義/手動でコピーする必要があります。

ロード()

デフォルトでは、関連するモデルを事前にフェッチせずにテーブルを参照しても、ormarは関連するモデルを構築しますが、pk値のみを使用します。load()メソッドを呼び出すことで、関連するモデルを読み込むことができます。

load()は、他のプロセスによって変更された場合、データベースからモデルを更新するためにも使用できます。

1
2
3
4
5
6
7
track=await Track. object.get(name='The Bird')
track.album.pk#はmalibuアルバムpk(1)を返します
track.album.name#はNoneを返します

#最初に実際にデータを読み込む必要があります。
track. bum.load()を待ちます。
track.album.name#は'Malibu'を返します

すべてを読み込む()

load_all(follow: bool = False, exclude: Union[List, str, Set, Dict] = None) -> Model

メソッドはload()と同様に動作しますが、メソッドを呼び出したモデルのすべてのリレーションシップをトラバースし、データベースからリロードします。

デフォルトでは、load_allメソッドは、メソッドが呼び出されたモデルに直接関連する(1ステップ離れた)モデルのみをロードします。

ただし、follow=Trueパラメーターを指定して、ネストされたモデルを走査し、それらをすべてリレーショナルツリーにロードすることができます。

警告follow=True設定を使用したループ更新を回避するために、load_allはアクセス済みモデルのセットを保持し、アクセス済みモデルのネストロードを実行しません。

1
2
3
4
5
6
そのため、ダイヤモンドや円形のリレーションシップタイプがある場合は、手動でロードを実行する必要があります。

```python
# in example like this the second Street (coming from City) won't be load_all, so ZipCode won't be reloaded
Street -> District -> City -> Street -> ZipCode
```

このメソッドは、QuerySetの除外フィールドメソッドとまったく同じように動作するオプションの除外パラメーターも受け取ります。これにより、更新されている関連モデルからフィールドを削除したり、関連モデル全体をスキップしたりできます。

メソッドはデータベースクエリを実行するため、関連するモデルでのload()およびall()のネストされた呼び出しよりも効率的です。

!!!ヒント除外の詳細については、以下をお読みください。

!!!警告load_all()ではすべてのリレーションがクリアされるため、一部のネストされたモデルを除外すると、呼び出し後に空になります。

節約()

save()->自己

QuerySet. create()メソッドを使用するか、モデルを通常のpydanticモデルに初期化してからsave()メソッドを呼び出して新しいモデルを作成できます。

save()は、プライマリキーが設定されていないか、データベースにモデルが存在しない場合に、モデルに加えられた変更を保存するためにも使用できます。

save()メソッドは、モデルがデータベースに存在するかどうかをチェックしないため、存在する場合、既存のプライマリキーを使用してモデルを保存しようとすると、選択したデータベースバックエンドから整合性エラーが発生します。

1
2
3
4
5
track=Track(name='鳥')
awaittrack.save()#はモデルをデータベースに保持します

track=await Track. object.get(name='The Bird')
awaittrack.save()#は、pkが入力されると整合性エラーを発生させます

更新()

update(_columns: List[str] = None, **kwargs) -> self

QuerySet. update()メソッドを使用するか、モデルプロパティ(フィールド)を更新してupdate()メソッドを呼び出すことで、モデルを更新できます。

主キーを設定せずにモデルを更新しようとすると、ModelPersistenceError例外が発生します。

新しく作成したモデルを永続的に保存するには、save()またはupsert(**kwargs)メソッドを使用します。

1
2
track=await Track. object.get(name='The Bird')
await track. update(name='鳥が再び襲う')

モデルで選択したカラムのみをデータベースに更新するには、_columnパラメーターに更新するカラムのリストを指定します。

例では:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Movie(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100,nullable=False,name="title")
    year: int=ormar.Integer()
    利益: float=ormar.Float()

Terminator=await映画(name='Terminator', year=1984,利益=0.078).save()

terminator.name="ターミネーター2"
ターミネーター. year=1991
ターミネーター。利益=0.520

#名前のみを更新
_column=["name"])

#ターミネーターインスタンスがリロードされなかったことに注意してください。
assertターミネーター. year==1991

#しかし、DBからデータを読み込むと、更新されていないことがわかります。
awaitターミネーター. load()
assertターミネーター. year==1984

!!!警告update()はモデルのインスタンスを更新しないため、渡された_columnリストの列数よりも多くの列数を変更すると、モデルインスタンスの値がデータベースとは異なることに注意してください。

更新の挿入()

upsert(**kwargs)->自己

上記のsave()またはupdate(**kwargs)メソッドのプロキシです。

主キーを->に設定すると、updateメソッドが呼び出されます。

pkが設定されていない場合、save()メソッドが呼び出されます。

1
2
3
4
5
track=Track(name='鳥')
await track. upsert()#pkが空なのでsaveを呼び出します

track=await Track. object.get(name='The Bird')
await track. upsert(name='The Bird Strikes Again')#pkが既に設定されているためupdateを呼び出します

削除()

QuerySet. delete()メソッドを使用するか、モデルを使用してdelete()メソッドを呼び出してモデルを削除できます。

1
2
track=await Track. object.get(name='The Bird')
await track. delete()#データベースからモデルを削除します

!!!tipこのトレースオブジェクトはそのままで、データベース内のレコードのみが削除されることに注意してください。

関連を保存()

save_related(follow: bool = False, save_all: bool = False, exclude=Optional[Union[Set, Dict]]) -> None

メソッドは、メソッドを呼び出したモデルのすべてのリレーションシップを走査し、保存されていないモデルごとにupsert()メソッドを呼び出します。

モデルがいつ保存されるかを確認するには、上記の[保存状態]セクションを確認してください。

デフォルトでは、save_atedメソッドは、メソッドが呼び出されたモデルに直接関連付けられている(1ステップ離れた)モデルのみを保存します。

ただし、follow=Trueパラメーターを指定して、ネストされたモデルをトラバースし、それらをすべてリレーショナルツリーに保存できます。

デフォルトでは、save_atedは保存されていない状態のモデルのみを保存します。つまり、現在の範囲内で変更されています。

関連するすべてのメソッドを強制的に保存する場合は、save_all=Trueフラグを使用します。

特定のリレーションシップの保存をスキップしたい場合は、除外パラメータを渡すことができます。

Excludeは、独自のモデル関係のセットである場合もあれば、ネストされたアイテムを含むこともできる辞書である場合もあります。

!!!note save_atedの除外パラメーターはリレーショナルフィールド名のみを受け付けるため、他のフィールドを渡すと、とにかく保存されることに注意してください

!!!Note除外される可能性のある値に渡される構造の詳細については、Queryset. fieldメソッドドキュメントを参照してください。

警告follow=True設定を使用した循環更新を回避するために、save_atedはリレーショナルツリーの各ブランチにアクセス済みモデルのセットを保持し、アクセス済みモデルに対してネストされたsave_atedは実行されません。

1
そのため、循環リレーションタイプがある場合は、手動で更新を行う必要があります。

save_all=Trueとfollow=Trueを使用すると、save_ated()を使用してリレーショナルツリー全体を一度に保存できることに注意してください。

例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Department(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    部門名: str=ormar.String(max_length=100)


クラスコース(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    class_name: str=ormar.String(max_length=100)
    完了: bool=ormar.Boolean()
    Department:オプション[Department]=ormar. ForeignKey(Department)


class Student(ormar. Model):
    base_or_config. copy()

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    コース=ormar. ManyTomany(コース)

保存する={
            "部門名":"Ormar",
            "コース":[
                {"コース名":"basic 1",
                 "完了": True,
                 "学生":[
                     {"name": "Jack"},
                     {"name": "Abi"}
                 ]},
                {"コース名":"basic 2",
                 "完了": True,
                 "学生":[
                     {"name": "Kate"},
                     {"name": "Miranda"}
                 ]
                 },
            ],
        }
#ツリー全体を初期化する
Department=Department(**to_save)

#一度にすべてを保存する(次々と)
await部門. save_関連(follow=True,save_all=True)

Department_check=await Department. object.select_all(follow=True).get()

除外する={
    "id":.。。、
    "コース":{
        "id":.。。、
        "学生": {"id", "studentcourse"}
    }
}
#IDを除外した後、モデルを通じて、以前と全く同じペイロードを得ることができます。
#ツリー全体を構築する
assert部門_チェック. model_dump(除外=to_除外)==to_保存

警告save_ated()は、すべてのリレーションシップとすべてのモデルを反復し、それらを1つずつ更新するため、すべてのモデルを保存しますが、データベースクエリの数に関しては最適ではない可能性があります。