Skip to content

聚合函数

目前支持 6 种聚合函数。

  • count(distinct: bool = True) -> int

  • 存在() -> 布尔值

  • 总和(列)-> 任意

  • 平均值(列)-> 任意

  • 分钟(列)-> 任意

  • 最大(列)-> 任意

  • 查询集代理

    • QuerysetProxy.count(distinct=True) 方法
    • QuerysetProxy.exists() 方法
    • QuerysetProxy.sum(columns) 方法
    • QuerysetProxy.avg(columns) 方法
    • QuerysetProxy.min(column) 方法
    • QuerysetProxy.max(列) 方法

数数

count(distinct: bool = True) -> int

返回与给定条件匹配的行数(即应用过滤器和排除)。如果distinct为True(默认值),这将返回选定的主行数。如果为 False,则计数将是返回的总行数(包括一对多或多对多左 select_lated 表连接的额外行)。 False 是依赖于它的工作流的遗留(有缺陷的)行为。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Book(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=databases.Database(DATABASE_URL),
        metadata=sqlalchemy.MetaData(),
        tablename="book"
    )

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=200)
    author: str = ormar.String(max_length=100)
    genre: str = ormar.String(
        max_length=100,
        default="Fiction",
        choices=["Fiction", "Adventure", "Historic", "Fantasy"],
    )


# returns count of rows in db for Books model
no_of_books = await Book.objects.count()

存在

存在() -> 布尔值

返回一个布尔值以确认是否有符合给定条件的行(与过滤器和排除一起应用)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Book(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=databases.Database(DATABASE_URL),
        metadata=sqlalchemy.MetaData(),
        tablename="book"
    )

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=200)
    author: str = ormar.String(max_length=100)
    genre: str = ormar.String(
        max_length=100,
        default="Fiction",
        choices=["Fiction", "Adventure", "Historic", "Fantasy"],
    )


# returns a boolean value if given row exists
has_sample = await Book.objects.filter(title='Sample').exists()

总和(列)-> 任意

返回与给定条件匹配的行的列的总和值(应用过滤器,如果之前设置则排除)。

您可以传递一个或多个列名称,包括相关列。

截至目前,传递的每一列都是单独聚合的(因此 sum(col1+col2) 是不可能的,您可以使用 sum(col1, col2) ,然后在 python 中添加 2 个返回的总和)

您不能对非数字列求和。

如果对一列进行聚合,则直接返回单个值作为结果 如果对多列进行聚合,则返回包含 column: 结果对的字典

给定模型如下

 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
from typing import Optional

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

database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()


base_ormar_config = ormar.OrmarConfig(
    metadata=metadata,
    database=database,
)


class Author(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"])

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


class Book(ormar.Model):

    ormar_config = base_ormar_config.copy(
        tablename="books", order_by=["year", "-ranking"]
    )

    id: int = ormar.Integer(primary_key=True)
    author: Optional[Author] = ormar.ForeignKey(Author)
    title: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    ranking: int = ormar.Integer(nullable=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
author = await Author(name="Author 1").save()
await Book(title="Book 1", year=1920, ranking=3, author=author).save()
await Book(title="Book 2", year=1930, ranking=1, author=author).save()
await Book(title="Book 3", year=1923, ranking=5, author=author).save()

assert await Book.objects.sum("year") == 5773
result = await Book.objects.sum(["year", "ranking"])
assert result == dict(year=5773, ranking=9)

try:
    # cannot sum string column
    await Book.objects.sum("title")
except ormar.QueryDefinitionError:
    pass

assert await Author.objects.select_related("books").sum("books__year") == 5773
result = await Author.objects.select_related("books").sum(
    ["books__year", "books__ranking"]
)
assert result == dict(books__year=5773, books__ranking=9)

assert (
    await Author.objects.select_related("books")
    .filter(books__year__lt=1925)
    .sum("books__year")
    == 3843
)

平均

平均值(列)-> 任意

返回匹配给定条件的行的列的平均值(应用过滤器,如果之前设置则排除)。

您可以传递一个或多个列名称,包括相关列。

截至目前,传递的每一列都是单独聚合的(因此 sum(col1+col2) 是不可能的,您可以使用 sum(col1, col2) ,然后在 python 中添加 2 个返回的总和)

您不能对非数字列求平均值。

如果对一列进行聚合,则直接返回单个值作为结果 如果对多列进行聚合,则返回包含 column: 结果对的字典

 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
from typing import Optional

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

database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()


base_ormar_config = ormar.OrmarConfig(
    metadata=metadata,
    database=database,
)


class Author(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"])

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


class Book(ormar.Model):

    ormar_config = base_ormar_config.copy(
        tablename="books", order_by=["year", "-ranking"]
    )

    id: int = ormar.Integer(primary_key=True)
    author: Optional[Author] = ormar.ForeignKey(Author)
    title: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    ranking: int = ormar.Integer(nullable=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
author = await Author(name="Author 1").save()
await Book(title="Book 1", year=1920, ranking=3, author=author).save()
await Book(title="Book 2", year=1930, ranking=1, author=author).save()
await Book(title="Book 3", year=1923, ranking=5, author=author).save()

assert round(float(await Book.objects.avg("year")), 2) == 1924.33
result = await Book.objects.avg(["year", "ranking"])
assert round(float(result.get("year")), 2) == 1924.33
assert result.get("ranking") == 3.0

try:
    # cannot avg string column
    await Book.objects.avg("title")
except ormar.QueryDefinitionError:
    pass

result = await Author.objects.select_related("books").avg("books__year")
assert round(float(result), 2) == 1924.33
result = await Author.objects.select_related("books").avg(
    ["books__year", "books__ranking"]
)
assert round(float(result.get("books__year")), 2) == 1924.33
assert result.get("books__ranking") == 3.0

assert (
    await Author.objects.select_related("books")
    .filter(books__year__lt=1925)
    .avg("books__year")
    == 1921.5
)

分钟

分钟(列)-> 任意

返回匹配给定条件的行的列的最小值(与过滤器一起应用,如果之前设置则排除)。

您可以传递一个或多个列名称,包括相关列。

截至目前,传递的每一列都是单独聚合的(因此 sum(col1+col2) 是不可能的,您可以使用 sum(col1, col2) ,然后在 python 中添加 2 个返回的总和)

如果对一列进行聚合,则直接返回单个值作为结果 如果对多列进行聚合,则返回包含 column: 结果对的字典

 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
from typing import Optional

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

database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()


base_ormar_config = ormar.OrmarConfig(
    metadata=metadata,
    database=database,
)


class Author(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"])

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


class Book(ormar.Model):

    ormar_config = base_ormar_config.copy(
        tablename="books", order_by=["year", "-ranking"]
    )

    id: int = ormar.Integer(primary_key=True)
    author: Optional[Author] = ormar.ForeignKey(Author)
    title: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    ranking: int = ormar.Integer(nullable=True)

示例用法可能如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
author = await Author(name="Author 1").save()
await Book(title="Book 1", year=1920, ranking=3, author=author).save()
await Book(title="Book 2", year=1930, ranking=1, author=author).save()
await Book(title="Book 3", year=1923, ranking=5, author=author).save()

assert await Book.objects.min("year") == 1920
result = await Book.objects.min(["year", "ranking"])
assert result == dict(year=1920, ranking=1)

assert await Book.objects.min("title") == "Book 1"

assert await Author.objects.select_related("books").min("books__year") == 1920
result = await Author.objects.select_related("books").min(
    ["books__year", "books__ranking"]
)
assert result == dict(books__year=1920, books__ranking=1)

assert (
    await Author.objects.select_related("books")
    .filter(books__year__gt=1925)
    .min("books__year")
    == 1930
)

最大限度

最大(列)-> 任意

返回匹配给定条件的行的列的最大值(与过滤器一起应用,如果之前设置则排除)。

返回匹配给定条件的行的列的最小值(与过滤器一起应用,如果之前设置则排除)。

您可以传递一个或多个列名称,包括相关列。

截至目前,传递的每一列都是单独聚合的(因此 sum(col1+col2) 是不可能的,您可以使用 sum(col1, col2) ,然后在 python 中添加 2 个返回的总和)

如果对一列进行聚合,则直接返回单个值作为结果 如果对多列进行聚合,则返回包含 column: 结果对的字典

 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
from typing import Optional

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

database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()


base_ormar_config = ormar.OrmarConfig(
    metadata=metadata,
    database=database,
)


class Author(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename="authors", order_by=["-name"])

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


class Book(ormar.Model):

    ormar_config = base_ormar_config.copy(
        tablename="books", order_by=["year", "-ranking"]
    )

    id: int = ormar.Integer(primary_key=True)
    author: Optional[Author] = ormar.ForeignKey(Author)
    title: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    ranking: int = ormar.Integer(nullable=True)

示例用法可能如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
author = await Author(name="Author 1").save()
await Book(title="Book 1", year=1920, ranking=3, author=author).save()
await Book(title="Book 2", year=1930, ranking=1, author=author).save()
await Book(title="Book 3", year=1923, ranking=5, author=author).save()

assert await Book.objects.max("year") == 1930
result = await Book.objects.max(["year", "ranking"])
assert result == dict(year=1930, ranking=5)

assert await Book.objects.max("title") == "Book 3"

assert await Author.objects.select_related("books").max("books__year") == 1930
result = await Author.objects.select_related("books").max(
    ["books__year", "books__ranking"]
)
assert result == dict(books__year=1930, books__ranking=5)

assert (
    await Author.objects.select_related("books")
    .filter(books__year__lt=1925)
    .max("books__year")
    == 1923
)

QuerysetProxy 方法

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

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

数数

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

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

存在

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

与上面的 sum 函数完全相同,但允许您对关系另一端的相关对象的列进行求和。

平均

与上面的 avg 函数完全相同,但允许您对关系另一端的相关对象的列进行平均。

分钟

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

最大限度

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

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