コンテンツにスキップ

データのフィルタリングとソート

次のメソッドを使用してデータをフィルタリングできます(sql where句)。

  • filter(*args, **kwargs) -> QuerySet

  • exclude(*args, **kwargs) -> QuerySet

  • get(*args,**kwargs)->モデル

  • get_or_none(*args, **kwargs) -> Optional[Model]

  • get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs) -> Tuple[Model, bool]

  • all(*args, **kwargs) -> List[Optional[Model]]

  • クエリセットエージェント

    • QuerysetProxy.filter(*args, **kwargs) 方法
    • QuerysetProxy.exclude(*args, **kwargs) 方法
    • QuerysetProxy.get(*args, **kwargs) 方法
    • QuerysetProxy.get_or_none(*args, **kwargs) 方法
    • QuerysetProxy.get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs) 方法
    • QuerysetProxy.all(*args, **kwargs) 方法

と、次のメソッドを使用してデータをソートします(sql order by句)。

  • order_by(columns:Union[List, str, OrderAction]) -> QuerySet
  • クエリセットエージェント
    • QuerysetProxy.order_by(columns:Union[List, str, OrderAction]) 方法

フィルタリング

フィルタリング

filter(*args, **kwargs) -> QuerySet

クロスFKリレーションシップのフィルターを使用して、任意のモデルプロパティ/フィールドでインスタンスをフィルタリングおよび取得できます。

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

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    is_best_セラー: bool=ormar.Boolean(デフォルト=False)

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

    id: int=ormar.Integer(プライマリキー=True)
    アルバム:オプション[Album]=ormar. ForeignKey(Album)
    name: str=ormar.String(max_length=100)
    位置: int=ormar.Integer()
    play_count: int=ormar.Integer(nullable=True)


track=Track. object.filter(name="The Bird").get()
#'The Bird'と等しい名前のトラックを返します

tracks=Track. object.filter(Album__name="Fantasies").all()
#列のアルバム名が'Fantasies'のすべてのトラックを返します。

Djangoスタイルのフィルター

特別なフィルタサフィックスを使用して、フィルタオペランドを変更できます。

  • 精密-値と正確に一致し、sql列=*はアルバム__name__正確='Malibu'と書くことができます。
  • i正確-sql列=を正確に一致させる(大文字と小文字を区別しない)
    • はアルバム__name__i正確='malibu'と書くことができます。
  • が含まれています-sql列LIKE'%%'*はアルバム__name__include='Mal'と書くことができます。
  • icontains-sql列LIKE'%%'(大文字と小文字を区別しない)*はアルバム__name__icontains='mal'と書くことができます。
  • はsqlで column IN (<VALUE1>, <VALUE2>, ...)*album__name__in=['Malibu', 'Barclay'] と書くことができる
  • isnull SQL列IS NULL(およびSQL列IS NOT NULL)
    • はalbum__name__isnull=True(isnotnull album__name_\isnull=False)と書くことができる
  • gt-sql列>(大きい)*position_\gt=3と書くことができる
  • gte-sql列>=(以上)*position_\gte=3と書くことができる
  • lt-sql列<(下)*position_=3と書くことができる
  • lte-sql列<=(以下)*position_\lte=3と書くことができる
  • startswith-sql列LIKE'%'(正確な開始マッチング)*アルバム__name__startswith='Mal'と書くことができます。
  • istartswithsql列LIKE'%'(大文字と小文字を区別しない)*album__name__istartswith='mal' と書くことができる
  • endswith-sql列LIKE'%'(正確な終了マッチング)*アルバムと書くことができます__名前__endswith='ibu'
  • iendswith-sql列LIKE'%'(大文字と小文字を区別しない)*アルバムと書くことができます__名前__iendswith='IBU'

いくつかのサンプル:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#sql:(product.name='Test'AND product. rate>=3.0)
Product. object.filter(name='Test',rating__gte=3.0).get()

#sql:(product.name='Test'AND product. rate>=3.0)
#OR(categories.nameIN('おもちゃ','本'))
製品.オブジェクト.フィルター(
    または_(
        ormar. and_(name='Test',rating__gte=3.0),
        カテゴリ__name__in=['おもちゃ','本'])
    ). get()
#note: and_と_についての詳細を読むか、以下の複雑なフィルターセクションを読んでください。

Pythonスタイルのフィルター

  • 正確-値と正確に一致し、SQL列=
    • Malibuと書くことTrack.album.nameできます。
  • i正確-正確に一致するsql列=(大文字と小文字を区別しない)
    • 書くことができます Track.album.name.iexact('malibu')
  • には-sql列LIKE'%%'*はTrack.album.name%'Mal')*は Track.album.name.contains('Mal') と書くことができる
  • icontens-sql列LIKE'%%'(大文字と小文字を区別しない)*Track.album.name.icontains('mal') と書くことができる
  • はsqlで column IN (<VALUE1>, <VALUE2>, ...)*は Track.album.name << ['Malibu', 'Barclay']*は Track.album.name.in_(['Malibu', 'Barclay']) と書くことができる
  • isnul-sql列IS NULL(およびsql列IS NOT NULL)*はTrack.album.nameと書くことができます>>None*はTrack.album.nameと書くことができます. isnull(True)*はと書くことができます Not nullは Track.album.name.isnull(False)*not nullとして書くことができます~(Track.album.name>>None)*not nullは ~(Track.album.name.isnull(True)) と書くことができます
  • gt-sql列>(大きい)*はTrack.album.name>3と書くことができる
  • gte-sql列>=(以上)*Track.album.name>=3と書くことができる
  • lt-sql列<(下)*はTrack.album.name<3と書くことができる
  • lte-sql列<=(以下等しい)*はTrack.album.name<=3と書くことができる
  • startswithsql列LIKE'%'(正確な開始マッチング)*Track.album.name.startswith('Mal') と書くことができます
  • istartswithsql列LIKE'%'(大文字と小文字を区別しない)*Track.album.name.istartswith('mal') と書くことができる
  • endswithsql列LIKE'%'(正確な終了マッチング)*Track.album.name.endswith('ibu') と書くことができます
  • iendswithsql列LIKE'%'(大文字小文字を区別しない)*Track.album.name.iendswith('IBU') と書くことができる

いくつかのサンプル:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#sql:(product.name='Test'AND product. rate>=3.0)
製品.オブジェクト.フィルター(
    (Product.name=='テスト')&(製品.レーティング>=3.0)
). get()

#sql:(product.name='Test'AND product. rate>=3.0)
#OR(categories.nameIN('おもちゃ','本'))
製品.オブジェクト.フィルター(
        ((Product.name=='テスト')&(製品評価>=3.0))|
        (Product.categories.name<<['おもちゃ','本'])
    ). get()

!!!ローを返さないすべてのメソッドは、QuerySetインスタンスを明示的に返すため、それらをリンクできます

1
2
3
そのため、`filter()`、`select_related()`、`limit()`、`offset()` などの操作をチェーン化することができます。

のようなもの `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

!!!警告「%ワイルドカード」は自分のために追加されたものであることに注意してください。「%」を検索値に含めると、エスケープされ、テキスト内のテキストのパーセント記号として扱われます。

除外する

exclude(*args, **kwargs) -> QuerySet

フィルターとまったく同じように動作し、すべての修飾子(接尾辞)は同じですが、not条件を返します。

したがって、filter(name='John')を使用すると、SQLのwhere name='John'に等しくなります。

条件は全て連結しているので、複数の値を渡すと条件和集合になるので注意してください。

除外(name='John', age>=35)は where not (name='John' and age>=35)

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

    id: int=ormar.Integer(プライマリキー=True)
    name: str=ormar.String(max_length=100)
    is_best_セラー: bool=ormar.Boolean(デフォルト=False)

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

    id: int=ormar.Integer(プライマリキー=True)
    アルバム:オプション[Album]=ormar. ForeignKey(Album)
    name: str=ormar.String(max_length=100)
    位置: int=ormar.Integer()
    play_count: int=ormar.Integer(nullable=True)


notes=awaitトラック.オブジェクト.除外(position_gt=3). all()
#位置<3のすべてのトラックを返します

複雑なフィルタ(ORを含む)

デフォルトでは、filter()メソッドとout()メソッドの両方が、filter(name="John", age__gt=30) を WHERE name = 'John' AND age > 30 に変換するためのAND条件とともに提供されるフィルタオプションを組み合わせます。

時には、WHERE name = 'John' OR age > 30 のように組み合わせて適用すべきではない条件クエリデータベースを使用したり、より制御したい複雑なwhereクエリを構築したりすると便利です。結局のところ、WHERE (name = 'John' OR age > 30) and city='New York' は WHERE name = 'John' OR (age > 30 and city='New York') とはまったく異なります。

ORとネストされた条件をビルドするために、ormarはQuerySetとQuerysetProxyのfilter()とout of()で使用できる2つの関数を提供します。

!!!noteこれらのメソッドは、*argsを受け入れる他のメソッド(get()やall()など)で提供できることに注意してください。

or_とand_の呼び出しは、互いに入れ子にしたり、キーワード引数と組み合わせたりすることができます。実際よりも複雑に聞こえるので、いくつかの例を見てみましょう。

このようなサンプルモデルが与えられた場合:

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


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

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


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

    id: int=ormar.Integer(プライマリキー=True)
    著者:オプション[著者]=ormar. ForeignKey(著者)
    title: str=ormar.String(max_length=100)
    year: int=ormar.Integer(nullable=True)

いくつかのサンプルデータを作成してみましょう。

1
2
3
4
5
6
7
tolkien=await Author(name="J. R.R.Tolkien").save()
await Book(Author=tolkien, title="The Hobbit",year=1933).save()
await Book(著者=tolkien、タイトル="The Lord of the Rings"、年=1955)。save()
await Book(Author=tolkien, title="The Silmarillion",year=1977).save()
sapkowski=await Author(name="Andrzej Sapkowski"). save()
await Book(Author=sapkowski, title="The Witcher",year=1990).save()
await Book(Author=sapkowski, title="The Tower of Fools",year=2002).save()

いくつかのサンプルを構築できます。

トールキンの本か1970年以降に書かれた本を選びましょう

SQL: WHERE ( authors.name = 'J.R.R. Tolkien' OR books.year > 1970 )

ジャンゴスタイル

1
2
3
4
5
6
本=(
    await Book. object.select_関連("著者")
    . filter(ormar.or_(Author__name="J.R.R.Tolkien",year__gt=1970))
    . all()
)
len(books)==5をアサートする

Pythonスタイル

1
2
3
4
5
6
本=(
    await Book. object.select_関連("著者")
    . filter((Book.author.name=="J.R.R.Tolkien")|(Book.year>1970))
    . all()
)
len(books)==5をアサートする

ここで、トールキンが1960年以降または1940年以前に書いた本を選択します。

SQL: WHERE ( books.year > 1960 OR books.year < 1940 ) AND authors.name = 'J.R.R. Tolkien'

ジャンゴスタイル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#オプション1-分割して別々の呼び出しにする
本=(
    await Book. object.select_関連("著者")
    . filter(ormar.or_(year__gt=1960,year__lt=1940))
    . filter(Author__name="J.R.R.Tolkien")
    . all()
)
書籍の長さ==2

#オプション2-オールインワン
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        ormar.と_(
            ormar. or_(year__gt=1960,year__lt=1940),
            Author__name="J. R.R.トールキン",
        )
    )
    . all()
)

書籍の長さ==2
assert books[0]. title=="ホビット"
書籍を主張する[1]. title=="シルマリオン"

Pythonスタイル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
本=(
    await Book. object.select_関連("著者")
    . filter((Book.year>1960)|(Book.year<1940))
    . filter(Book.author.name=="J.R.R.Tolkien")
    . all()
)
書籍の長さ==2

#オプション2-オールインワン
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        (
            (Book. year>1960)|(Book.year<1940)
        )&(Book.author.name=="J. R.R.トールキン")
    )
    . all()
)

書籍の長さ==2
assert books[0]. title=="ホビット"
書籍を主張する[1]. title=="シルマリオン"

2000年以前のサプコフスキーの本や1960年以降のトルキンの本

SQL: WHERE ( ( books.year > 1960 AND authors.name = 'J.R.R. Tolkien' ) OR ( books.year < 2000 AND authors.name = 'Andrzej Sapkowski' ) )

ジャンゴスタイル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        または_(
            ormar. and_(year__gt=1960,Author__name="J.R.R.Tolkien"),
            ormar. and_(year__lt=2000,Author__name="Andrzej Sapkowski"),
        )
    )
    . all()
)
書籍の長さ==2

Pythonスタイル

1
2
3
4
5
6
7
8
9
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        ((Book. year>1960)&(Book.author.name=="J.R.R.Tolkien"))|
        ((Book. year<2000)&(Book.author.name=="Andrzej Sapkowski"))
    )
    . all()
)
書籍の長さ==2

もちろん、これらの関数は2つ以上の条件を持つことができるので、「hobbit」の本を含めたい場合は:

SQL: WHERE ( ( books.year > 1960 AND authors.name = 'J.R.R. Tolkien' ) OR ( books.year < 2000 AND os0cec_authors.name = 'Andrzej Sapkowski' ) OR books.title LIKE '%hobbit%' )

ジャンゴスタイル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        または_(
            ormar. and_(year__gt=1960,Author__name="J.R.R.Tolkien"),
            ormar. and_(year__lt=2000,Author__name="Andrzej Sapkowski"),
            title__icontains="hobbit",
        )
    )
    . all()
)

Pythonスタイル

1
2
3
4
5
6
7
8
9
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        ((Book. year>1960)&(Book.author.name=="J.R.R.Tolkien"))|
        ((Book. year<2000)&(Book.author.name=="Andrzej Sapkowski"))|
        (Book. title.icontains("hobbit"))
    )
    . all()
)

必要に応じて、次のクエリを実装するなど、必要に応じてより深い条件をネストできます。

SQL:

1
2
3
WHERE((books. year>1960またはbooks.year<1940)
ANDauthors.name='J. R.R.トールキン')OR
(books. year<2000 ANDauthors.name='Andrzej Sapkowski'))

クエリは次のように構築できます。

ジャンゴスタイル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        または_(
            ormar.と_(
                ormar. or_(year__gt=1960,year__lt=1940),
                Author__name="J. R.R.トールキン",
            ),
            ormar. and_(year__lt=2000,Author__name="Andrzej Sapkowski"),
        )
    )
    . all()
)
len(books)==3をアサートする
assert books[0]. title=="ホビット"
書籍を主張する[1]. title=="シルマリオン"
assert books[2]. title=="The Witcher"

Pythonスタイル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
本=(
    await Book. object.select_関連("著者")
    フィルタ(
        (
            (
            (本。年>1960)|
            (本。年<1940年)
            ) &
            (Book.author.name=="J. R.R.トールキン")
        ) |
        (
            (Book. year<2000)&
            (Book.author.name=="Andrzej Sapkowski")
        )
    )
    . all()
)
len(books)==3をアサートする
assert books[0]. title=="ホビット"
書籍を主張する[1]. title=="シルマリオン"
assert books[2]. title=="The Witcher"

これで、ormar. or_とormar.and_がどのように動作するかを理解したはずです。もちろん、それらをクエリセットの他のメソッドにリンクすることもできるので、例では、完全に有効なクエリは次のようになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
本=(
    await Book. object.select_関連("著者")
    . filter(ormar.or_(year__gt=1980,Author__name="Andrzej Sapkowski"))
    . filter(title__startswith="The")
    リミット(1)
    オフセット(1)
    . order_by("-id")
    . all()
)
len(books)==1をアサートする
assert books[0]. title=="The Witcher"

Pythonスタイルのリンクやネストについても同様です。

ジャンゴスタイル

注意点としては、djangoスタイルでは同じキーワード引数を複数回指定することはできないため、以下のような filter(ormar.or_(name='Jack', name='John')) のクエリは許可されません。同じカラムの値を複数チェックしたい場合は、in演算子:filter(name__in=['Jack','John']) を使うだけです。

引数を1つだけor_またはand_関数に渡すと、括弧で囲まれているだけで、実際のクエリには影響しないため、最終的には3つのクエリすべてが同じになります。

1
2
3
await Book. object.filter(title='The Hobbit').get()
await Book. object.filter(ormar.or_(title='The Hobbit')).get()
await Book. object.filter(ormar.and_(title='The Hobbit')).get()

!!!note注意or_とand_のクエリにはWHERE(title='The Hobbit')がありますが、括弧は不要で実際の効果はありません。

どうしても同じフィールド名を2回使う必要がある場合は、この機能を使うことができます。同じキーワード引数を関数に2回渡すことはできないので、サンプルで WHERE (authors.name LIKE '%tolkien%') OR (authors.name LIKE '%sapkowski%')) をクエリする方法を覚えておいてください。

あなたはこれを行うことはできません:

1
2
3
4
5
6
7
8
本=(
    await Book. object.select_関連("著者")
        . filter(ormar.or_)
        Author__name__icontains="tolkien",
        Author__name__icontains="sapkowski"#or_で同じキーワードを2回使用することはできません!
    ))#Python構文エラー
        . all()
)

しかし、あなたはそれを行うことができます:

1
2
3
4
5
6
7
8
9
本=(
    await Book. object.select_関連("著者")
        . filter(ormar.or_)
        ormar. and_(Author__name__icontains="tolkien"),#one引数==ちょうど()で包まれた
        ormar. and_(Author__name__icontains="sapkowski")
    ))
        . all()
)
len(books)==5をアサートする

Pythonスタイル

Pythonスタイルでは、同じフィールドを何度でも使用できることに注意してください。

1
2
3
4
5
6
7
8
本=(
    await Book. object.select_関連("著者")
        フィルタ(
        (Book.author.name. icontains("tolkien"))|
        (Book.author.name. icontains("sapkowski"))
    ))                                      
        . all()
)

得る

get(*args,**kwargs)->モデル

kwargsの設定条件を満たす最初の行をデータベースから取得します。

任意のargsおよび/またはkwargsを渡す場合、filter(*args,**kwargs). get()を呼び出すのと同等のショートカットです

!!!tipフィルターの詳細については、フィルターを参照してください。

1
についてもっと読む `get` 行く [読む/得る](../read/#get)

取得またはなし

上記のgetとまったく同じですが、条件に一致するデータベースレコードが見つからない場合は例外をスローする代わりにNoneを返します。

取得または作成

get_or_create(_defaults: Optional[Dict[str, Any]] = None, *args, **kwargs) -> Tuple[Model, bool]

メソッドの作成と取得の組み合わせです。

これは、任意のargsやkwargsを渡すときに呼び出すのと同じショートカットです filter(*args, **kwargs).get_or_create()

!!!tipフィルターの詳細については、フィルターを参照してください。

1
`get_or_create` の詳細については、[にアクセスしてください。](../read/#get_or_create)を読んでください。

!!!警告指定されたアイテムが存在しない場合、(自動増分でない限り)Prime_keyカラムを含むがこれらに限定されない、モデルのすべての必須フィールドにkwargsを渡す必要があります。

全部

all(*args, **kwargs) -> List[Optional["Model"]]

設定されたフィルターオプションの場合、特定のモデルのデータベース内のすべてのローが返されます。

kwargsを渡すときは、filter(*args,**kwargs). all()を呼び出すのと同じショートカットです

!!!tipフィルターの詳細については、フィルターを参照してください。

1
`all` についてもっと読むには[を読む/すべて](../read/#all)

QuerysetProxyメソッド

関連するManyTomanyフィールドとReverseForeignKeyに直接アクセスする場合は、関連するモデルのリストを返します。

ただし、QuerySet APIのサブセットを公開しているため、親モデルから直接フィルタリング、作成、関連モデルの選択などを行うことができます。

フィルタリング

上記のフィルタリング機能と全く同じですが、関連するオブジェクトをリレーションシップの反対側からフィルタリングすることができます。

!!!ヒントQuerysetProxyの詳細については、querysetproxyセクションにアクセスしてください

除外する

上記の除外機能とまったく同じですが、関係の反対側から関連オブジェクトをフィルタリングすることができます。

!!!ヒントQuerysetProxyの詳細については、querysetproxyセクションにアクセスしてください

得る

上記のget関数と全く同じですが、関連するオブジェクトをリレーションの反対側からフィルタリングすることができます。

!!!ヒントQuerysetProxyの詳細については、querysetproxyセクションにアクセスしてください

取得またはなし

上記のgetとまったく同じですが、条件に一致するデータベースレコードが見つからない場合は例外をスローする代わりにNoneを返します。

取得または作成

上記のget_or_create関数と全く同じですが、関連するオブジェクトをリレーションシップの反対側からフィルタリングすることができます。

!!!ヒントQuerysetProxyの詳細については、querysetproxyセクションにアクセスしてください

全部

上記のすべての機能とまったく同じですが、関係の反対側から関連するオブジェクトをフィルタリングできます。

!!!ヒントQuerysetProxyの詳細については、querysetproxyセクションにアクセスしてください

並べ替え

注文の根拠

order_by(columns: Union[List, str, OrderAction]) -> QuerySet

order_by()を使用すると、選択したフィールドに基づいてデータベースの結果を並べ替えることができます。

フィールド名を持つ文字列、または異なるフィールドを持つ文字列のリストを指定できます。

SQLの並べ替えは、order_byで指定した名前の順に適用されます。

!!!tipデフォルトでは、並べ替えを指定しないか、すべてのプライマリキーで明示的に並べ替えます

!!!警告ネストされたモデルでソートすると、結果行がメインモデルでソートされなくなります。そうしないと、marはこれらのサブ行をメインモデルにマージします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
サンプルの生のデータベース行の結果(子モデルdescでソート):
```
MODEL: 1 - Child Model - 3
MODEL: 2 - Child Model - 2
MODEL: 1 - Child Model - 1
```

結果は2行の結果になります:
```
MODEL: 1 - Child Models: [3, 1] # encountered first in result, all children rows combined
MODEL: 2 - Child Models: [2]
```

メインモデルが結果に重複することはありません。

与えられたサンプルモデルは次のとおりです。

 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
import asyncio

import databases
import ormar
import sqlalchemy
from examples import create_drop_database

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL),
    metadata=sqlalchemy.MetaData(),
)


class Owner(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="owners")

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Toy(ormar.Model):
    ormar_config = ormar_base_config.copy(tablename="toys")

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    owner: Owner = ormar.ForeignKey(Owner)


@create_drop_database(base_config=ormar_base_config)
async def run_query():
    # build some sample data
    aphrodite = await Owner.objects.create(name="Aphrodite")
    hermes = await Owner.objects.create(name="Hermes")
    zeus = await Owner.objects.create(name="Zeus")

    await Toy.objects.create(name="Toy 4", owner=zeus)
    await Toy.objects.create(name="Toy 5", owner=hermes)
    await Toy.objects.create(name="Toy 2", owner=aphrodite)
    await Toy.objects.create(name="Toy 1", owner=zeus)
    await Toy.objects.create(name="Toy 3", owner=aphrodite)
    await Toy.objects.create(name="Toy 6", owner=hermes)


asyncio.run(run_query())

マスターモデルフィールドで並べ替えるには、フィールド名を指定するだけです

ジャンゴスタイル

1
2
3
4
5
6
おもちゃ=awaitおもちゃ.オブジェクト.選択関連("所有者"). order_by("名前").all()
assert[x.name. replace("Toy","")for x in Toys]==[
    str(x+1)for x in range(6)
]
assertトイズ[0].オーナー==ゼウス
アサート玩具[1].オーナー==アフロディーテ

Pythonスタイル

1
2
3
4
5
6
おもちゃ=awaitおもちゃ.オブジェクト. select_関連("所有者").order_by(Toy.name.asc()).all()
assert[x.name. replace("Toy","")for x in Toys]==[
    str(x+1)for x in range(6)
]
assertおもちゃ[0].オーナー==ゼウス
アサート玩具[1].オーナー==アフロディーテ

ネストされたモデルを並べ替えるには、dunder'__'でフィールド名を区切ります。

このようにして、すべてのリレーションシップタイプ->ForeignKey、逆仮想FK、およびManyTomanyフィールドを並べ替えることができます。

ジャンゴスタイル

1
2
3
4
おもちゃ=awaitおもちゃ.オブジェクト.選択関連("所有者"). order_by("所有者__名前").all()
assertトイズ[0].owner.name==トイズ[1].owner.name=="アフロディーテ"
アサートトイズ[2].owner.name==トイズ[3].owner.name=="エルメス"
アサートトイズ[4].owner.name==トイズ[5].owner.name=="Zeus"

Pythonスタイル

1
2
3
4
おもちゃ=awaitおもちゃ.オブジェクト. select_関連("所有者").order_by(Toy.owner.name.asc()).all()
assertトイズ[0].owner.name==トイズ[1].owner.name=="アフロディーテ"
アサートトイズ[2].owner.name==トイズ[3].owner.name=="エルメス"
アサートトイズ[4].owner.name==トイズ[5].owner.name=="Zeus"

降順で並べ替えるには、フィールド名の前にハイフンを付けます

ジャンゴスタイル

1
2
3
4
5
6
7
8
オーナー=(
    await所有者。オブジェクト。選択関連("おもちゃ")
        . order_by("-toys__name")
        . filter(name="Zeus")
        . get()
)
assertowner.toys[0]. name=="おもちゃ4"
アサートowner.toys[1]. name=="おもちゃ1"

Pythonスタイル

1
2
3
4
5
6
7
8
オーナー=(
    await所有者。オブジェクト。選択関連("おもちゃ")
        . order_by(Owner.toys.name.desc())
        . filter(Owner.name=="Zeus")
        . get()
)
assertowner.toys[0]. name=="おもちゃ4"
アサートowner.toys[1]. name=="おもちゃ1"

!!!ローを返さないすべてのメソッドは、QuerySetインスタンスを明示的に返すため、それらをリンクできます

1
2
3
そのため、`filter()`、`select_related()`、`limit()`、`offset()` などの操作を連鎖させることができます。

のようなもの `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

ormarのデフォルトのソート

データベース内の行の順序は保証されていないため、自分で順序を指定しなくても、ormarは常に各(部分的な)クエリにorder by sql句を発行します。

デフォルトでは、指定されたモデルを使用してデータベースにクエリを実行する場合、モデルはPrime_keyカラムの昇順でソートされます。デフォルトの動作を変更するには、ormar_configにorder_byパラメータを指定します。

!!!ヒントモデルの並べ替え順序の詳細については、ドキュメントのモデルセクションを参照してください

デフォルトでは、リレーションシップは同じ順序に従いますが、オーダー_byおよび関連する_order_byパラメーターをリレーションシップに提供することで、クエリ中に関連するモデルがロードされる順序を変更できます。

!!!ヒントモデルの並べ替え順序の詳細については、ドキュメントのリレーショナルセクションを参照してください

order_by句の適用順序は以下の通りです:

  • クエリでorder_by()呼び出しを明示的に渡す
  • オーダー\byと関連するオーダー\by(存在する場合)による関係
  • モデルのormar_configオブジェクトorder_by
  • モデルの主要な_keyカラムの昇順(バックアップ、上記のいずれも提供されていない場合に使用)

1つのソースからの注文のみが各モデルに適用されます(単一のクエリで常に上書きできるように)。

つまり、クエリでモデルに明示的なorder_byを指定すると、リレーションシップとモデルのソート順序がスキップされます。

リレーションシップ1を指定すると、モデルの並べ替えはスキップされます。

最後に、Modelに提供した場合、主_keyのデフォルト値はスキップされます。

QuerysetProxyメソッド

関連するManyTomanyフィールドとReverseForeignKeyに直接アクセスする場合は、関連するモデルのリストを返します。

ただし、QuerySet APIのサブセットを公開しているため、親モデルから直接フィルタリング、作成、関連モデルの選択などを行うことができます。

注文の根拠

上記のorder_by関数と全く同じですが、関連するオブジェクトをリレーションの反対側からソートすることができます。

!!!ヒントQuerysetProxyの詳細については、querysetproxyセクションにアクセスしてください