Skip to content

选择列的子集

要仅选择模型中选定的列,您可以使用以下函数。

  • fields(columns: Union[List, str, set, dict]) -> QuerySet

  • exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet

  • 查询集代理

    • QuerysetProxy.fields(columns: Union[List, str, set, dict]) 方法
    • QuerysetProxy.exclude_fields(columns: Union[List, str, set, dict]) 方法

领域

fields(columns: Union[List, str, set, dict]) -> QuerySet

使用 fields(),您可以选择模型列的子集来限制数据负载。

注意 注意 fields() 和 except_fields() 既适用于主模型(在普通查询上,如 get、all 等),也适用于 select_lated 和 prefetch_lated 模型(使用嵌套表示法)。

给出如下示例数据:

 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
60
61
62
63
64
65
import asyncio

import databases
import ormar
import sqlalchemy
from examples import create_drop_database
from tests.settings import DATABASE_URL

base_ormar_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL, force_rollback=True),
    metadata=sqlalchemy.MetaData(),
)


class Company(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename="companies")

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


class Car(ormar.Model):
    ormar_config = base_ormar_config.copy()

    id: int = ormar.Integer(primary_key=True)
    manufacturer = ormar.ForeignKey(Company)
    name: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    gearbox_type: str = ormar.String(max_length=20, nullable=True)
    gears: int = ormar.Integer(nullable=True)
    aircon_type: str = ormar.String(max_length=20, nullable=True)


@create_drop_database(base_config=base_ormar_config)
async def sample_data():
    # build some sample data
    toyota = await Company.objects.create(name="Toyota", founded=1937)
    await Car.objects.create(
        manufacturer=toyota,
        name="Corolla",
        year=2020,
        gearbox_type="Manual",
        gears=5,
        aircon_type="Manual",
    )
    await Car.objects.create(
        manufacturer=toyota,
        name="Yaris",
        year=2019,
        gearbox_type="Manual",
        gears=5,
        aircon_type="Manual",
    )
    await Car.objects.create(
        manufacturer=toyota,
        name="Supreme",
        year=2020,
        gearbox_type="Auto",
        gears=6,
        aircon_type="Auto",
    )


asyncio.run(sample_data())

您可以通过传递一个来选择指定的字段 str, List[str], Set[str] or dict 具有嵌套定义。

要包含相关模型,请使用符号 {related_name}__{column}[__{optional_next} etc.]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
all_cars = await (
    Car.objects
    .select_related('manufacturer')
    .fields(['id', 'name', 'manufacturer__name'])
    .all()
)
for car in all_cars:
    # excluded columns will yield None
    assert all(getattr(car, x) is None for x in ['year', 'gearbox_type', 'gears', 'aircon_type'])
    # included column on related models will be available, pk column is always included
    # even if you do not include it in fields list
    assert car.manufacturer.name == 'Toyota'
    # also in the nested related models - you cannot exclude pk - it's always auto added
    assert car.manufacturer.founded is None

fields() 可以被调用多次,构建要选择的列。

如果您将相关模型包含到 select_lated() 调用中,但您不会在字段中为这些模型指定列

  • 意味着这些嵌套模型的所有字段的列表。

    all_cars = await ( Car.objects .select_related('manufacturer') .fields('id') .fields(['name']) .all() )

    all fields from company model are selected

    assert all_cars[0].manufacturer.name == 'Toyota' assert all_cars[0].manufacturer.founded == 1937

!!! warning 不能排除强制字段,因为它会引发 ValidationError,要排除字段必须为空。

1
2
The `values()` method can be used to exclude mandatory fields, though data will
be returned as a `dict`.

您不能排除强制型号列 - 本示例中的制造商__名称。

1
2
3
4
5
6
7
await (
    Car.objects
    .select_related('manufacturer')
    .fields(['id', 'name', 'manufacturer__founded'])
    .all()
)
# will raise pydantic ValidationError as company.name is required

!!!tip Pk 列不能被排除 - 即使没有明确包含,它也总是自动添加。

您还可以传递要包含为字典或集的字段。

要将字段标记为包含在字典中,请使用其名称作为键,使用省略号作为值。

要遍历嵌套模型,请使用嵌套字典。

要包含最后一级的字段而不是嵌套字典,可以使用集合。

要包含整个嵌套模型,请指定模型相关的字段名称和省略号。

您可以在下面看到等效的示例:

 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
60
61
62
63
64
65
66
# 1. like in example above
await (
    Car.objects
    .select_related('manufacturer')
    .fields(['id', 'name', 'manufacturer__name'])
    .all()
)

# 2. to mark a field as required use ellipsis
await (
    Car.objects
    .select_related('manufacturer')
    .fields({'id': ...,
             'name': ...,
             'manufacturer': {
                 'name': ...
                }
             })
    .all()
)

# 3. to include whole nested model use ellipsis
await (
    Car.objects
    .select_related('manufacturer')
    .fields({'id': ...,
             'name': ...,
             'manufacturer': ...
             })
    .all()
)

# 4. to specify fields at last nesting level 
# you can also use set - equivalent to 2. above
await (
    Car.objects
    .select_related('manufacturer')
    .fields({'id': ...,
             'name': ...,
             'manufacturer': {'name'}
             })
    .all()
)

# 5. of course set can have multiple fields
await (
    Car.objects
    .select_related('manufacturer')
    .fields({'id': ...,
             'name': ...,
             'manufacturer': {'name', 'founded'}
             })
    .all()
)

# 6. you can include all nested fields, 
# but it will be equivalent of 3. above which is shorter
await (
    Car.objects
    .select_related('manufacturer')
    .fields({'id': ...,
             'name': ...,
             'manufacturer': {'id', 'name', 'founded'}
             })
    .all()
)

!!!注意所有不返回行的方法显式返回一个 QuerySet 实例,以便您可以将它们链接在一起

1
2
3
So operations like `filter()`, `select_related()`, `limit()` and `offset()` etc. can be chained.

Something like `Track.objects.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

排除字段

exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet

使用 except_fields(),您可以选择将排除的模型列的子集以限制数据加载。

它与 fields() 方法相反,因此请检查上面的文档以了解可用的选项。

特别是检查上面如何传递嵌套字典和集合作为掩码以从整个层次结构中排除字段。

注意 注意 fields() 和 except_fields() 既适用于主模型(在普通查询上,如 get、all 等),也适用于 select_lated 和 prefetch_lated 模型(使用嵌套表示法)。

您可以在下面找到一些简单的示例:

  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
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import asyncio

import databases
import ormar
import sqlalchemy
from examples import create_drop_database
from tests.settings import DATABASE_URL

base_ormar_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL, force_rollback=True),
    metadata=sqlalchemy.MetaData(),
)


class Company(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename="companies")

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


class Car(ormar.Model):
    ormar_config = base_ormar_config.copy()

    id: int = ormar.Integer(primary_key=True)
    manufacturer = ormar.ForeignKey(Company)
    name: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    gearbox_type: str = ormar.String(max_length=20, nullable=True)
    gears: int = ormar.Integer(nullable=True)
    aircon_type: str = ormar.String(max_length=20, nullable=True)


@create_drop_database(base_config=base_ormar_config)
async def sample_data():
    # build some sample data
    toyota = await Company.objects.create(name="Toyota", founded=1937)
    await Car.objects.create(
        manufacturer=toyota,
        name="Corolla",
        year=2020,
        gearbox_type="Manual",
        gears=5,
        aircon_type="Manual",
    )
    await Car.objects.create(
        manufacturer=toyota,
        name="Yaris",
        year=2019,
        gearbox_type="Manual",
        gears=5,
        aircon_type="Manual",
    )
    await Car.objects.create(
        manufacturer=toyota,
        name="Supreme",
        year=2020,
        gearbox_type="Auto",
        gears=6,
        aircon_type="Auto",
    )


asyncio.run(sample_data())


# select manufacturer but only name,
# to include related models use notation {model_name}__{column}
all_cars = await (
    Car.objects
    .select_related('manufacturer')
    .exclude_fields([
        'year',
        'gearbox_type',
        'gears',
        'aircon_type',
        'company__founded'
    ])
    .all()
)
for car in all_cars:
    # excluded columns will yield None
    assert all(getattr(car, x) is None
               for x in [
                   'year',
                   'gearbox_type',
                   'gears',
                   'aircon_type'
               ])
    # included column on related models will be available,
    # pk column is always included
    # even if you do not include it in fields list
    assert car.manufacturer.name == 'Toyota'
    # also in the nested related models,
    # you cannot exclude pk - it's always auto added
    assert car.manufacturer.founded is None

# fields() can be called several times,
# building up the columns to select
# models included in select_related 
# but with no columns in fields list implies all fields
all_cars = await (
    Car.objects
    .select_related('manufacturer')
    .exclude_fields('year')
    .exclude_fields(['gear', 'gearbox_type'])
    .all()
)
# all fields from company model are selected
assert all_cars[0].manufacturer.name == 'Toyota'
assert all_cars[0].manufacturer.founded == 1937

# cannot exclude mandatory model columns,
# company__name in this example - note usage of dict/set this time
await (
    Car.objects
    .select_related('manufacturer')
    .exclude_fields([{'company': {'name'}}])
    .all()
)
# will raise pydantic ValidationError as company.name is required

!!!警告 无法排除强制字段,因为它会引发 ValidationError,要排除字段,它必须可以为空。

1
2
The `values()` method can be used to exclude mandatory fields, though data will
be returned as a `dict`.

!!!提示 Pk 列无法排除 - 即使明确排除,它也始终会自动添加。

!!!注意所有不返回行的方法显式返回一个 QuerySet 实例,以便您可以将它们链接在一起

1
2
3
So operations like `filter()`, `select_related()`, `limit()` and `offset()` etc. can be chained.

Something like `Track.object.select_related("album").filter(album__name="Malibu").offset(1).limit(1).all()`

QuerysetProxy 方法

当直接访问相关的ManyToMany字段以及ReverseForeignKey时,返回相关模型的列表。

但同时它公开了 QuerySet API 的子集,因此您可以直接从父模型过滤、创建、选择相关模型等。

领域

与上面的字段功能完全相同,但允许您从关系另一端的相关对象中选择列。

!!!tip 要了解有关 QuerysetProxy 的更多信息,请访问 querysetproxy 部分

排除字段

与上面的 except_fields 函数完全相同,但允许您从关系另一端的相关对象中选择列。

!!!tip 要了解有关 QuerysetProxy 的更多信息,请访问 querysetproxy 部分