数据库函数

下面记录的类为用户提供了一种方法,可以使用底层数据库提供的函数作为注释、聚合或过滤器在 Django 中使用。函数也是 表达式,因此它们可以与其他表达式一起使用和组合,例如 聚合函数

我们将在每个函数的示例中使用以下模型

class Author(models.Model):
    name = models.CharField(max_length=50)
    age = models.PositiveIntegerField(null=True, blank=True)
    alias = models.CharField(max_length=50, null=True, blank=True)
    goes_by = models.CharField(max_length=50, null=True, blank=True)

我们通常不建议允许 null=True 用于 CharField,因为这允许该字段具有两个“空值”,但这对于下面的 Coalesce 示例很重要。

比较和转换函数

Cast

class Cast(expression, output_field)

强制 expression 的结果类型为 output_field 中的类型。

用法示例

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cast
>>> Author.objects.create(age=25, name="Margaret Smith")
>>> author = Author.objects.annotate(
...     age_as_float=Cast("age", output_field=FloatField()),
... ).get()
>>> print(author.age_as_float)
25.0

Coalesce

class Coalesce(*expressions, **extra)

接受至少两个字段名或表达式的列表,并返回第一个非空值(注意,空字符串不被视为空值)。每个参数必须是类似的类型,因此混合文本和数字会导致数据库错误。

用法示例

>>> # Get a screen name from least to most public
>>> from django.db.models import Sum
>>> from django.db.models.functions import Coalesce
>>> Author.objects.create(name="Margaret Smith", goes_by="Maggie")
>>> author = Author.objects.annotate(screen_name=Coalesce("alias", "goes_by", "name")).get()
>>> print(author.screen_name)
Maggie

>>> # Prevent an aggregate Sum() from returning None
>>> # The aggregate default argument uses Coalesce() under the hood.
>>> aggregated = Author.objects.aggregate(
...     combined_age=Sum("age"),
...     combined_age_default=Sum("age", default=0),
...     combined_age_coalesce=Coalesce(Sum("age"), 0),
... )
>>> print(aggregated["combined_age"])
None
>>> print(aggregated["combined_age_default"])
0
>>> print(aggregated["combined_age_coalesce"])
0

警告

除非显式转换为正确的数据库类型,否则传递给 MySQL 上的 Coalesce 的 Python 值可能会被转换为不正确的类型

>>> from django.db.models import DateTimeField
>>> from django.db.models.functions import Cast, Coalesce
>>> from django.utils import timezone
>>> now = timezone.now()
>>> Coalesce("updated", Cast(now, DateTimeField()))

Collate

class Collate(expression, collation)

接受一个表达式和一个排序规则名称来查询。

例如,要在 SQLite 中进行不区分大小写的过滤

>>> Author.objects.filter(name=Collate(Value("john"), "nocase"))
<QuerySet [<Author: John>, <Author: john>]>

它也可以在排序时使用,例如使用 PostgreSQL

>>> Author.objects.order_by(Collate("name", "et-x-icu"))
<QuerySet [<Author: Ursula>, <Author: Veronika>, <Author: Ülle>]>

Greatest

class Greatest(*expressions, **extra)

接受至少两个字段名或表达式的列表,并返回最大值。每个参数必须是类似的类型,因此混合文本和数字会导致数据库错误。

用法示例

class Blog(models.Model):
    body = models.TextField()
    modified = models.DateTimeField(auto_now=True)


class Comment(models.Model):
    body = models.TextField()
    modified = models.DateTimeField(auto_now=True)
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
>>> from django.db.models.functions import Greatest
>>> blog = Blog.objects.create(body="Greatest is the best.")
>>> comment = Comment.objects.create(body="No, Least is better.", blog=blog)
>>> comments = Comment.objects.annotate(last_updated=Greatest("modified", "blog__modified"))
>>> annotated_comment = comments.get()

annotated_comment.last_updated 将是 blog.modifiedcomment.modified 中最晚的。

警告

当一个或多个表达式可能为 null 时,Greatest 的行为在不同的数据库之间有所不同

  • PostgreSQL:Greatest 将返回最大的非空表达式,或者如果所有表达式都为 null,则返回 null
  • SQLite、Oracle 和 MySQL:如果任何表达式为 nullGreatest 将返回 null

如果您知道要提供一个合理的最小值作为默认值,则可以使用 Coalesce 模拟 PostgreSQL 行为。

JSONObject

class JSONObject(**fields)

接受键值对列表,并返回包含这些对的 JSON 对象。

用法示例

>>> from django.db.models import F
>>> from django.db.models.functions import JSONObject, Lower
>>> Author.objects.create(name="Margaret Smith", alias="msmith", age=25)
>>> author = Author.objects.annotate(
...     json_object=JSONObject(
...         name=Lower("name"),
...         alias="alias",
...         age=F("age") * 2,
...     )
... ).get()
>>> author.json_object
{'name': 'margaret smith', 'alias': 'msmith', 'age': 50}

Least

class Least(*expressions, **extra)

接受至少两个字段名或表达式的列表,并返回最小值。每个参数必须是类似的类型,因此混合文本和数字会导致数据库错误。

警告

当一个或多个表达式可能为 null 时,Least 的行为在不同的数据库之间有所不同

  • PostgreSQL:Least 将返回最小的非空表达式,或者如果所有表达式都为 null,则返回 null
  • SQLite、Oracle 和 MySQL:如果任何表达式为 nullLeast 将返回 null

如果您知道要提供一个合理的最大值作为默认值,则可以使用 Coalesce 模拟 PostgreSQL 行为。

NullIf

class NullIf(expression1, expression2)

接受两个表达式,如果它们相等,则返回 None,否则返回 expression1

Oracle 上的注意事项

由于 Oracle 约定,当表达式为 CharField 类型时,此函数返回空字符串而不是 None

由于 Oracle 不接受 NULL 作为第一个参数,因此在 Oracle 上禁止将 Value(None) 传递给 expression1

日期函数

我们将在每个函数的示例中使用以下模型

class Experiment(models.Model):
    start_datetime = models.DateTimeField()
    start_date = models.DateField(null=True, blank=True)
    start_time = models.TimeField(null=True, blank=True)
    end_datetime = models.DateTimeField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)
    end_time = models.TimeField(null=True, blank=True)

Extract

class Extract(expression, lookup_name=None, tzinfo=None, **extra)

将日期的组成部分提取为数字。

接受一个表示 DateFieldDateTimeFieldTimeFieldDurationFieldexpression 和一个 lookup_name,并返回由 lookup_name 引用的日期部分作为 IntegerField。Django 通常使用数据库的 extract 函数,因此您可以使用数据库支持的任何 lookup_name。可以传递一个 tzinfo 子类(通常由 zoneinfo 提供)以在特定时区中提取值。

给定日期时间 2015-06-15 23:30:01.000321+00:00,内置的 lookup_name 返回

  • “year”: 2015
  • “iso_year”: 2015
  • “quarter”: 2
  • “month”: 6
  • “day”: 15
  • “week”: 25
  • “week_day”: 2
  • “iso_week_day”: 1
  • “hour”: 23
  • “minute”: 30
  • “second”: 1

如果 Django 中启用了不同的时区,例如 Australia/Melbourne,则日期时间将在提取值之前转换为该时区。上面的示例日期中墨尔本的时区偏移量为 +10:00。当此时区处于活动状态时返回的值将与上面相同,除了

  • “day”: 16
  • “week_day”: 3
  • “iso_week_day”: 2
  • “hour”: 9

week_day

week_day lookup_type 的计算方式与大多数数据库和 Python 的标准函数不同。此函数将为星期日返回 1,为星期一返回 2,一直到为星期六返回 7

Python 中的等效计算为

>>> from datetime import datetime
>>> dt = datetime(2015, 6, 15)
>>> (dt.isoweekday() % 7) + 1
2

week

根据 ISO-8601 标准计算 week lookup_type,即一周从星期一开始。一年的第一周是包含该年第一个星期四的那一周,即第一周的大部分(四天或更多)都在该年内。返回的值在 1 到 52 或 53 之间。

上面每个 lookup_name 都有一个对应的 Extract 子类(列在下面),通常应该使用它们,而不是更冗长的等效项,例如使用 ExtractYear(...) 而不是 Extract(..., lookup_name='year')

用法示例

>>> from datetime import datetime
>>> from django.db.models.functions import Extract
>>> start = datetime(2015, 6, 15)
>>> end = datetime(2015, 7, 2)
>>> Experiment.objects.create(
...     start_datetime=start, start_date=start.date(), end_datetime=end, end_date=end.date()
... )
>>> # Add the experiment start year as a field in the QuerySet.
>>> experiment = Experiment.objects.annotate(
...     start_year=Extract("start_datetime", "year")
... ).get()
>>> experiment.start_year
2015
>>> # How many experiments completed in the same year in which they started?
>>> Experiment.objects.filter(start_datetime__year=Extract("end_datetime", "year")).count()
1

DateField 提取

class ExtractYear(expression, tzinfo=None, **extra)
lookup_name = 'year'
class ExtractIsoYear(expression, tzinfo=None, **extra)

返回 ISO-8601 周编号年。

lookup_name = 'iso_year'
class ExtractMonth(expression, tzinfo=None, **extra)
lookup_name = 'month'
class ExtractDay(expression, tzinfo=None, **extra)
lookup_name = 'day'
class ExtractWeekDay(expression, tzinfo=None, **extra)
lookup_name = 'week_day'
class ExtractIsoWeekDay(expression, tzinfo=None, **extra)

返回 ISO-8601 星期,星期一为 1,星期日为 7。

lookup_name = 'iso_week_day'
class ExtractWeek(expression, tzinfo=None, **extra)
lookup_name = 'week'
class ExtractQuarter(expression, tzinfo=None, **extra)
lookup_name = 'quarter'

这些逻辑上等效于 Extract('date_field', lookup_name)。每个类也是一个在 DateFieldDateTimeField 上注册的 Transform,作为 __(lookup_name),例如 __year

由于 DateField 没有时间部分,因此只有处理日期部分的 Extract 子类才能与 DateField 一起使用。

>>> from datetime import datetime, timezone
>>> from django.db.models.functions import (
...     ExtractDay,
...     ExtractMonth,
...     ExtractQuarter,
...     ExtractWeek,
...     ExtractIsoWeekDay,
...     ExtractWeekDay,
...     ExtractIsoYear,
...     ExtractYear,
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
...     start_datetime=start_2015,
...     start_date=start_2015.date(),
...     end_datetime=end_2015,
...     end_date=end_2015.date(),
... )
>>> Experiment.objects.annotate(
...     year=ExtractYear("start_date"),
...     isoyear=ExtractIsoYear("start_date"),
...     quarter=ExtractQuarter("start_date"),
...     month=ExtractMonth("start_date"),
...     week=ExtractWeek("start_date"),
...     day=ExtractDay("start_date"),
...     weekday=ExtractWeekDay("start_date"),
...     isoweekday=ExtractIsoWeekDay("start_date"),
... ).values(
...     "year",
...     "isoyear",
...     "quarter",
...     "month",
...     "week",
...     "day",
...     "weekday",
...     "isoweekday",
... ).get(
...     end_date__year=ExtractYear("start_date")
... )
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
 'day': 15, 'weekday': 2, 'isoweekday': 1}

DateTimeField 提取

除了以下内容外,上面列出的所有针对 DateField 的提取也可以用于 DateTimeField

class ExtractHour(expression, tzinfo=None, **extra)
lookup_name = 'hour'
class ExtractMinute(expression, tzinfo=None, **extra)
lookup_name = 'minute'
class ExtractSecond(expression, tzinfo=None, **extra)
lookup_name = 'second'

这些逻辑上等效于 Extract('datetime_field', lookup_name)。每个类也是一个在 DateTimeField 上注册的 Transform,作为 __(lookup_name),例如 __minute

DateTimeField 示例

>>> from datetime import datetime, timezone
>>> from django.db.models.functions import (
...     ExtractDay,
...     ExtractHour,
...     ExtractMinute,
...     ExtractMonth,
...     ExtractQuarter,
...     ExtractSecond,
...     ExtractWeek,
...     ExtractIsoWeekDay,
...     ExtractWeekDay,
...     ExtractIsoYear,
...     ExtractYear,
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
...     start_datetime=start_2015,
...     start_date=start_2015.date(),
...     end_datetime=end_2015,
...     end_date=end_2015.date(),
... )
>>> Experiment.objects.annotate(
...     year=ExtractYear("start_datetime"),
...     isoyear=ExtractIsoYear("start_datetime"),
...     quarter=ExtractQuarter("start_datetime"),
...     month=ExtractMonth("start_datetime"),
...     week=ExtractWeek("start_datetime"),
...     day=ExtractDay("start_datetime"),
...     weekday=ExtractWeekDay("start_datetime"),
...     isoweekday=ExtractIsoWeekDay("start_datetime"),
...     hour=ExtractHour("start_datetime"),
...     minute=ExtractMinute("start_datetime"),
...     second=ExtractSecond("start_datetime"),
... ).values(
...     "year",
...     "isoyear",
...     "month",
...     "week",
...     "day",
...     "weekday",
...     "isoweekday",
...     "hour",
...     "minute",
...     "second",
... ).get(
...     end_datetime__year=ExtractYear("start_datetime")
... )
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
 'day': 15, 'weekday': 2, 'isoweekday': 1, 'hour': 23, 'minute': 30,
 'second': 1}

USE_TZTrue 时,日期时间以 UTC 存储在数据库中。如果 Django 中启用了不同的时区,则在提取值之前将日期时间转换为该时区。以下示例转换为墨尔本时区(UTC +10:00),这会更改返回的日期、星期几和小时值。

>>> from django.utils import timezone
>>> import zoneinfo
>>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")  # UTC+10:00
>>> with timezone.override(melb):
...     Experiment.objects.annotate(
...         day=ExtractDay("start_datetime"),
...         weekday=ExtractWeekDay("start_datetime"),
...         isoweekday=ExtractIsoWeekDay("start_datetime"),
...         hour=ExtractHour("start_datetime"),
...     ).values("day", "weekday", "isoweekday", "hour").get(
...         end_datetime__year=ExtractYear("start_datetime"),
...     )
...
{'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}

显式地将时区传递给 Extract 函数的行为相同,并且优先于活动时区。

>>> import zoneinfo
>>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
>>> Experiment.objects.annotate(
...     day=ExtractDay("start_datetime", tzinfo=melb),
...     weekday=ExtractWeekDay("start_datetime", tzinfo=melb),
...     isoweekday=ExtractIsoWeekDay("start_datetime", tzinfo=melb),
...     hour=ExtractHour("start_datetime", tzinfo=melb),
... ).values("day", "weekday", "isoweekday", "hour").get(
...     end_datetime__year=ExtractYear("start_datetime"),
... )
{'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}

Now

class Now

在执行查询时返回数据库服务器的当前日期和时间,通常使用 SQL CURRENT_TIMESTAMP

用法示例

>>> from django.db.models.functions import Now
>>> Article.objects.filter(published__lte=Now())
<QuerySet [<Article: How to Django>]>

PostgreSQL 注意事项

在 PostgreSQL 上,SQL CURRENT_TIMESTAMP 返回当前事务开始的时间。因此,为了跨数据库兼容性,Now() 使用 STATEMENT_TIMESTAMP 代替。如果您需要事务时间戳,请使用 django.contrib.postgres.functions.TransactionNow

Oracle

在 Oracle 上,SQL LOCALTIMESTAMP 用于避免将 CURRENT_TIMESTAMP 转换为 DateTimeField 时出现的问题。

Django 4.2 中的变更

添加了对 MySQL 上微秒精度和 SQLite 上毫秒精度的支持。

Django 5.0 中的变更

在旧版本中,Oracle 上使用 SQL CURRENT_TIMESTAMP 而不是 LOCALTIMESTAMP

Trunc

class Trunc(expression, kind, output_field=None, tzinfo=None, **extra)

将日期截断到一个重要的组成部分。

当您只关心某件事是否发生在特定年份、小时或日期,而不关心确切的秒数时,Trunc(及其子类)可以用于过滤或聚合您的数据。例如,您可以使用 Trunc 来计算每天的销售额。

Trunc 接受一个表示 DateFieldTimeFieldDateTimeField 的单个 expression,一个表示日期或时间部分的 kind,以及一个 output_field,它可以是 DateTimeField()TimeField()DateField()。它根据 output_field 返回一个日期时间、日期或时间,并将字段截断到 kind 的最小值。如果省略 output_field,它将默认为 expressionoutput_field。一个 tzinfo 子类,通常由 zoneinfo 提供,可以传递给它来在特定时区截断值。

给定日期时间 2015-06-15 14:30:50.000321+00:00,内置的 kind 返回

  • “year”: 2015-01-01 00:00:00+00:00
  • “quarter”: 2015-04-01 00:00:00+00:00
  • “month”: 2015-06-01 00:00:00+00:00
  • “week”: 2015-06-15 00:00:00+00:00
  • “day”: 2015-06-15 00:00:00+00:00
  • “hour”: 2015-06-15 14:00:00+00:00
  • “minute”: 2015-06-15 14:30:00+00:00
  • “second”: 2015-06-15 14:30:50+00:00

如果 Django 中启用了不同的时区,例如 Australia/Melbourne,则日期时间将在截断值之前转换为新时区。在上面的示例日期中,墨尔本的时区偏移量为 +10:00。当此时区处于活动状态时返回的值将为

  • “year”: 2015-01-01 00:00:00+11:00
  • “quarter”: 2015-04-01 00:00:00+10:00
  • “month”: 2015-06-01 00:00:00+10:00
  • “week”: 2015-06-16 00:00:00+10:00
  • “day”: 2015-06-16 00:00:00+10:00
  • “hour”: 2015-06-16 00:00:00+10:00
  • “minute”: 2015-06-16 00:30:00+10:00
  • “second”: 2015-06-16 00:30:50+10:00

年份的偏移量为 +11:00,因为结果过渡到了夏令时。

上面每个 kind 都有一个相应的 Trunc 子类(列在下面),通常应该使用它们而不是更冗长的等效项,例如使用 TruncYear(...) 而不是 Trunc(..., kind='year')

子类都被定义为转换,但它们没有注册到任何字段,因为查找名称已经被 Extract 子类保留。

用法示例

>>> from datetime import datetime
>>> from django.db.models import Count, DateTimeField
>>> from django.db.models.functions import Trunc
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 30, 50, 321))
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 40, 2, 123))
>>> Experiment.objects.create(start_datetime=datetime(2015, 12, 25, 10, 5, 27, 999))
>>> experiments_per_day = (
...     Experiment.objects.annotate(
...         start_day=Trunc("start_datetime", "day", output_field=DateTimeField())
...     )
...     .values("start_day")
...     .annotate(experiments=Count("id"))
... )
>>> for exp in experiments_per_day:
...     print(exp["start_day"], exp["experiments"])
...
2015-06-15 00:00:00 2
2015-12-25 00:00:00 1
>>> experiments = Experiment.objects.annotate(
...     start_day=Trunc("start_datetime", "day", output_field=DateTimeField())
... ).filter(start_day=datetime(2015, 6, 15))
>>> for exp in experiments:
...     print(exp.start_datetime)
...
2015-06-15 14:30:50.000321
2015-06-15 14:40:02.000123

DateField 截断

class TruncYear(expression, output_field=None, tzinfo=None, **extra)
kind = 'year'
class TruncMonth(expression, output_field=None, tzinfo=None, **extra)
kind = 'month'
class TruncWeek(expression, output_field=None, tzinfo=None, **extra)

截断到星期一的午夜。

kind = 'week'
class TruncQuarter(expression, output_field=None, tzinfo=None, **extra)
kind = 'quarter'

这些在逻辑上等效于 Trunc('date_field', kind)。它们截断日期的所有部分,直到 kind,这允许以较低的精度对日期进行分组或过滤。 expression 可以具有 DateFieldDateTimeFieldoutput_field

由于 DateField 没有时间部分,因此只有处理日期部分的 Trunc 子类才能与 DateField 一起使用。

>>> from datetime import datetime, timezone
>>> from django.db.models import Count
>>> from django.db.models.functions import TruncMonth, TruncYear
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> start2 = datetime(2015, 6, 15, 14, 40, 2, 123, tzinfo=timezone.utc)
>>> start3 = datetime(2015, 12, 31, 17, 5, 27, 999, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> Experiment.objects.create(start_datetime=start2, start_date=start2.date())
>>> Experiment.objects.create(start_datetime=start3, start_date=start3.date())
>>> experiments_per_year = (
...     Experiment.objects.annotate(year=TruncYear("start_date"))
...     .values("year")
...     .annotate(experiments=Count("id"))
... )
>>> for exp in experiments_per_year:
...     print(exp["year"], exp["experiments"])
...
2014-01-01 1
2015-01-01 2

>>> import zoneinfo
>>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
>>> experiments_per_month = (
...     Experiment.objects.annotate(month=TruncMonth("start_datetime", tzinfo=melb))
...     .values("month")
...     .annotate(experiments=Count("id"))
... )
>>> for exp in experiments_per_month:
...     print(exp["month"], exp["experiments"])
...
2015-06-01 00:00:00+10:00 1
2016-01-01 00:00:00+11:00 1
2014-06-01 00:00:00+10:00 1

DateTimeField 截断

class TruncDate(expression, tzinfo=None, **extra)
lookup_name = 'date'
output_field = DateField()

TruncDateexpression 转换为日期,而不是使用内置的 SQL 截断函数。它也作为 __date 注册为 DateTimeField 上的转换。

class TruncTime(expression, tzinfo=None, **extra)
lookup_name = 'time'
output_field = TimeField()

TruncTimeexpression 转换为时间,而不是使用内置的 SQL 截断函数。它也作为 __time 注册为 DateTimeField 上的转换。

class TruncDay(expression, output_field=None, tzinfo=None, **extra)
kind = 'day'
class TruncHour(expression, output_field=None, tzinfo=None, **extra)
kind = 'hour'
class TruncMinute(expression, output_field=None, tzinfo=None, **extra)
kind = 'minute'
class TruncSecond(expression, output_field=None, tzinfo=None, **extra)
kind = 'second'

这些在逻辑上等效于 Trunc('datetime_field', kind)。它们截断日期时间的所有部分,直到 kind,并允许以较低的精度对日期时间进行分组或过滤。 expression 必须具有 DateTimeFieldoutput_field

用法示例

>>> from datetime import date, datetime, timezone
>>> from django.db.models import Count
>>> from django.db.models.functions import (
...     TruncDate,
...     TruncDay,
...     TruncHour,
...     TruncMinute,
...     TruncSecond,
... )
>>> import zoneinfo
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
>>> Experiment.objects.annotate(
...     date=TruncDate("start_datetime"),
...     day=TruncDay("start_datetime", tzinfo=melb),
...     hour=TruncHour("start_datetime", tzinfo=melb),
...     minute=TruncMinute("start_datetime"),
...     second=TruncSecond("start_datetime"),
... ).values("date", "day", "hour", "minute", "second").get()
{'date': datetime.date(2014, 6, 15),
 'day': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=zoneinfo.ZoneInfo('Australia/Melbourne')),
 'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=zoneinfo.ZoneInfo('Australia/Melbourne')),
 'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=timezone.utc),
 'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=timezone.utc)
}

TimeField 截断

class TruncHour(expression, output_field=None, tzinfo=None, **extra)
kind = 'hour'
class TruncMinute(expression, output_field=None, tzinfo=None, **extra)
kind = 'minute'
class TruncSecond(expression, output_field=None, tzinfo=None, **extra)
kind = 'second'

这些逻辑上等同于 Trunc('time_field', kind)。它们截断时间的所有部分,直到 kind,这允许对精度较低的时间进行分组或过滤。 expression 可以具有 output_field,它可以是 TimeFieldDateTimeField

由于 TimeField 没有日期部分,因此只有处理时间部分的 Trunc 子类才能与 TimeField 一起使用。

>>> from datetime import datetime, timezone
>>> from django.db.models import Count, TimeField
>>> from django.db.models.functions import TruncHour
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> start2 = datetime(2014, 6, 15, 14, 40, 2, 123, tzinfo=timezone.utc)
>>> start3 = datetime(2015, 12, 31, 17, 5, 27, 999, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_time=start1.time())
>>> Experiment.objects.create(start_datetime=start2, start_time=start2.time())
>>> Experiment.objects.create(start_datetime=start3, start_time=start3.time())
>>> experiments_per_hour = (
...     Experiment.objects.annotate(
...         hour=TruncHour("start_datetime", output_field=TimeField()),
...     )
...     .values("hour")
...     .annotate(experiments=Count("id"))
... )
>>> for exp in experiments_per_hour:
...     print(exp["hour"], exp["experiments"])
...
14:00:00 2
17:00:00 1

>>> import zoneinfo
>>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
>>> experiments_per_hour = (
...     Experiment.objects.annotate(
...         hour=TruncHour("start_datetime", tzinfo=melb),
...     )
...     .values("hour")
...     .annotate(experiments=Count("id"))
... )
>>> for exp in experiments_per_hour:
...     print(exp["hour"], exp["experiments"])
...
2014-06-16 00:00:00+10:00 2
2016-01-01 04:00:00+11:00 1

数学函数

我们将在数学函数示例中使用以下模型

class Vector(models.Model):
    x = models.FloatField()
    y = models.FloatField()

Abs

class Abs(expression, **extra)

返回数值字段或表达式的绝对值。

用法示例

>>> from django.db.models.functions import Abs
>>> Vector.objects.create(x=-0.5, y=1.1)
>>> vector = Vector.objects.annotate(x_abs=Abs("x"), y_abs=Abs("y")).get()
>>> vector.x_abs, vector.y_abs
(0.5, 1.1)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Abs
>>> FloatField.register_lookup(Abs)
>>> # Get vectors inside the unit cube
>>> vectors = Vector.objects.filter(x__abs__lt=1, y__abs__lt=1)

ACos

class ACos(expression, **extra)

返回数值字段或表达式的反余弦。表达式值必须在 -1 到 1 的范围内。

用法示例

>>> from django.db.models.functions import ACos
>>> Vector.objects.create(x=0.5, y=-0.9)
>>> vector = Vector.objects.annotate(x_acos=ACos("x"), y_acos=ACos("y")).get()
>>> vector.x_acos, vector.y_acos
(1.0471975511965979, 2.6905658417935308)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import ACos
>>> FloatField.register_lookup(ACos)
>>> # Get vectors whose arccosine is less than 1
>>> vectors = Vector.objects.filter(x__acos__lt=1, y__acos__lt=1)

ASin

class ASin(expression, **extra)

返回数值字段或表达式的反正弦。表达式值必须在 -1 到 1 的范围内。

用法示例

>>> from django.db.models.functions import ASin
>>> Vector.objects.create(x=0, y=1)
>>> vector = Vector.objects.annotate(x_asin=ASin("x"), y_asin=ASin("y")).get()
>>> vector.x_asin, vector.y_asin
(0.0, 1.5707963267948966)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import ASin
>>> FloatField.register_lookup(ASin)
>>> # Get vectors whose arcsine is less than 1
>>> vectors = Vector.objects.filter(x__asin__lt=1, y__asin__lt=1)

ATan

class ATan(expression, **extra)

返回数值字段或表达式的反正切。

用法示例

>>> from django.db.models.functions import ATan
>>> Vector.objects.create(x=3.12, y=6.987)
>>> vector = Vector.objects.annotate(x_atan=ATan("x"), y_atan=ATan("y")).get()
>>> vector.x_atan, vector.y_atan
(1.2606282660069106, 1.428638798133829)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import ATan
>>> FloatField.register_lookup(ATan)
>>> # Get vectors whose arctangent is less than 2
>>> vectors = Vector.objects.filter(x__atan__lt=2, y__atan__lt=2)

ATan2

class ATan2(expression1, expression2, **extra)

返回 expression1 / expression2 的反正切。

用法示例

>>> from django.db.models.functions import ATan2
>>> Vector.objects.create(x=2.5, y=1.9)
>>> vector = Vector.objects.annotate(atan2=ATan2("x", "y")).get()
>>> vector.atan2
0.9209258773829491

Ceil

class Ceil(expression, **extra)

返回大于或等于数值字段或表达式的最小整数。

用法示例

>>> from django.db.models.functions import Ceil
>>> Vector.objects.create(x=3.12, y=7.0)
>>> vector = Vector.objects.annotate(x_ceil=Ceil("x"), y_ceil=Ceil("y")).get()
>>> vector.x_ceil, vector.y_ceil
(4.0, 7.0)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Ceil
>>> FloatField.register_lookup(Ceil)
>>> # Get vectors whose ceil is less than 10
>>> vectors = Vector.objects.filter(x__ceil__lt=10, y__ceil__lt=10)

Cos

class Cos(expression, **extra)

返回数值字段或表达式的余弦。

用法示例

>>> from django.db.models.functions import Cos
>>> Vector.objects.create(x=-8.0, y=3.1415926)
>>> vector = Vector.objects.annotate(x_cos=Cos("x"), y_cos=Cos("y")).get()
>>> vector.x_cos, vector.y_cos
(-0.14550003380861354, -0.9999999999999986)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cos
>>> FloatField.register_lookup(Cos)
>>> # Get vectors whose cosine is less than 0.5
>>> vectors = Vector.objects.filter(x__cos__lt=0.5, y__cos__lt=0.5)

Cot

class Cot(expression, **extra)

返回数值字段或表达式的余切。

用法示例

>>> from django.db.models.functions import Cot
>>> Vector.objects.create(x=12.0, y=1.0)
>>> vector = Vector.objects.annotate(x_cot=Cot("x"), y_cot=Cot("y")).get()
>>> vector.x_cot, vector.y_cot
(-1.5726734063976826, 0.642092615934331)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cot
>>> FloatField.register_lookup(Cot)
>>> # Get vectors whose cotangent is less than 1
>>> vectors = Vector.objects.filter(x__cot__lt=1, y__cot__lt=1)

Degrees

class Degrees(expression, **extra)

将数值字段或表达式从弧度转换为度数。

用法示例

>>> from django.db.models.functions import Degrees
>>> Vector.objects.create(x=-1.57, y=3.14)
>>> vector = Vector.objects.annotate(x_d=Degrees("x"), y_d=Degrees("y")).get()
>>> vector.x_d, vector.y_d
(-89.95437383553924, 179.9087476710785)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Degrees
>>> FloatField.register_lookup(Degrees)
>>> # Get vectors whose degrees are less than 360
>>> vectors = Vector.objects.filter(x__degrees__lt=360, y__degrees__lt=360)

Exp

class Exp(expression, **extra)

返回 e(自然对数底)的值,该值被提升到数值字段或表达式的幂。

用法示例

>>> from django.db.models.functions import Exp
>>> Vector.objects.create(x=5.4, y=-2.0)
>>> vector = Vector.objects.annotate(x_exp=Exp("x"), y_exp=Exp("y")).get()
>>> vector.x_exp, vector.y_exp
(221.40641620418717, 0.1353352832366127)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Exp
>>> FloatField.register_lookup(Exp)
>>> # Get vectors whose exp() is greater than 10
>>> vectors = Vector.objects.filter(x__exp__gt=10, y__exp__gt=10)

Floor

class Floor(expression, **extra)

返回不大于数值字段或表达式的最大整数。

用法示例

>>> from django.db.models.functions import Floor
>>> Vector.objects.create(x=5.4, y=-2.3)
>>> vector = Vector.objects.annotate(x_floor=Floor("x"), y_floor=Floor("y")).get()
>>> vector.x_floor, vector.y_floor
(5.0, -3.0)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Floor
>>> FloatField.register_lookup(Floor)
>>> # Get vectors whose floor() is greater than 10
>>> vectors = Vector.objects.filter(x__floor__gt=10, y__floor__gt=10)

Ln

class Ln(expression, **extra)

返回数值字段或表达式的自然对数。

用法示例

>>> from django.db.models.functions import Ln
>>> Vector.objects.create(x=5.4, y=233.0)
>>> vector = Vector.objects.annotate(x_ln=Ln("x"), y_ln=Ln("y")).get()
>>> vector.x_ln, vector.y_ln
(1.6863989535702288, 5.4510384535657)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Ln
>>> FloatField.register_lookup(Ln)
>>> # Get vectors whose value greater than e
>>> vectors = Vector.objects.filter(x__ln__gt=1, y__ln__gt=1)

Log

class Log(expression1, expression2, **extra)

接受两个数值字段或表达式,并返回第二个以第一个为底的对数。

用法示例

>>> from django.db.models.functions import Log
>>> Vector.objects.create(x=2.0, y=4.0)
>>> vector = Vector.objects.annotate(log=Log("x", "y")).get()
>>> vector.log
2.0

Mod

class Mod(expression1, expression2, **extra)

接受两个数值字段或表达式,并返回第一个除以第二个的余数(模运算)。

用法示例

>>> from django.db.models.functions import Mod
>>> Vector.objects.create(x=5.4, y=2.3)
>>> vector = Vector.objects.annotate(mod=Mod("x", "y")).get()
>>> vector.mod
0.8

Pi

class Pi(**extra)

返回数学常数 π 的值。

Power

class Power(expression1, expression2, **extra)

接受两个数值字段或表达式,并返回第一个被提升到第二个幂的值。

用法示例

>>> from django.db.models.functions import Power
>>> Vector.objects.create(x=2, y=-2)
>>> vector = Vector.objects.annotate(power=Power("x", "y")).get()
>>> vector.power
0.25

Radians

class Radians(expression, **extra)

将数值字段或表达式从度数转换为弧度。

用法示例

>>> from django.db.models.functions import Radians
>>> Vector.objects.create(x=-90, y=180)
>>> vector = Vector.objects.annotate(x_r=Radians("x"), y_r=Radians("y")).get()
>>> vector.x_r, vector.y_r
(-1.5707963267948966, 3.141592653589793)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Radians
>>> FloatField.register_lookup(Radians)
>>> # Get vectors whose radians are less than 1
>>> vectors = Vector.objects.filter(x__radians__lt=1, y__radians__lt=1)

Random

class Random(**extra)

0.0 x < 1.0 范围内返回一个随机值。

Round

class Round(expression, precision=0, **extra)

将数值字段或表达式四舍五入到 precision(必须是整数)位小数。默认情况下,它四舍五入到最接近的整数。一半的值是向上还是向下舍入取决于数据库。

用法示例

>>> from django.db.models.functions import Round
>>> Vector.objects.create(x=5.4, y=-2.37)
>>> vector = Vector.objects.annotate(x_r=Round("x"), y_r=Round("y", precision=1)).get()
>>> vector.x_r, vector.y_r
(5.0, -2.4)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Round
>>> FloatField.register_lookup(Round)
>>> # Get vectors whose round() is less than 20
>>> vectors = Vector.objects.filter(x__round__lt=20, y__round__lt=20)

Sign

class Sign(expression, **extra)

返回数值字段或表达式的符号(-1、0、1)。

用法示例

>>> from django.db.models.functions import Sign
>>> Vector.objects.create(x=5.4, y=-2.3)
>>> vector = Vector.objects.annotate(x_sign=Sign("x"), y_sign=Sign("y")).get()
>>> vector.x_sign, vector.y_sign
(1, -1)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Sign
>>> FloatField.register_lookup(Sign)
>>> # Get vectors whose signs of components are less than 0.
>>> vectors = Vector.objects.filter(x__sign__lt=0, y__sign__lt=0)

Sin

class Sin(expression, **extra)

返回数值字段或表达式的正弦。

用法示例

>>> from django.db.models.functions import Sin
>>> Vector.objects.create(x=5.4, y=-2.3)
>>> vector = Vector.objects.annotate(x_sin=Sin("x"), y_sin=Sin("y")).get()
>>> vector.x_sin, vector.y_sin
(-0.7727644875559871, -0.7457052121767203)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Sin
>>> FloatField.register_lookup(Sin)
>>> # Get vectors whose sin() is less than 0
>>> vectors = Vector.objects.filter(x__sin__lt=0, y__sin__lt=0)

Sqrt

class Sqrt(expression, **extra)

返回非负数值字段或表达式的平方根。

用法示例

>>> from django.db.models.functions import Sqrt
>>> Vector.objects.create(x=4.0, y=12.0)
>>> vector = Vector.objects.annotate(x_sqrt=Sqrt("x"), y_sqrt=Sqrt("y")).get()
>>> vector.x_sqrt, vector.y_sqrt
(2.0, 3.46410)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Sqrt
>>> FloatField.register_lookup(Sqrt)
>>> # Get vectors whose sqrt() is less than 5
>>> vectors = Vector.objects.filter(x__sqrt__lt=5, y__sqrt__lt=5)

Tan

class Tan(expression, **extra)

返回数值字段或表达式的正切值。

用法示例

>>> from django.db.models.functions import Tan
>>> Vector.objects.create(x=0, y=12)
>>> vector = Vector.objects.annotate(x_tan=Tan("x"), y_tan=Tan("y")).get()
>>> vector.x_tan, vector.y_tan
(0.0, -0.6358599286615808)

它也可以注册为转换。例如

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Tan
>>> FloatField.register_lookup(Tan)
>>> # Get vectors whose tangent is less than 0
>>> vectors = Vector.objects.filter(x__tan__lt=0, y__tan__lt=0)

文本函数

Chr

class Chr(expression, **extra)

接受一个数值字段或表达式,并返回该表达式的文本表示形式,作为一个单一字符。它的工作原理与 Python 的 chr() 函数相同。

Length 一样,它可以注册为 IntegerField 上的转换。默认的查找名称是 chr

用法示例

>>> from django.db.models.functions import Chr
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.filter(name__startswith=Chr(ord("M"))).get()
>>> print(author.name)
Margaret Smith

Concat

class Concat(*expressions, **extra)

接受至少两个文本字段或表达式列表,并返回连接后的文本。每个参数必须是文本或字符类型。如果你想将一个 TextField() 与一个 CharField() 连接,那么一定要告诉 Django output_field 应该是一个 TextField()。在将 Value 连接起来时,也需要指定 output_field,如下面的示例所示。

此函数永远不会有空结果。在后端,如果空参数导致整个表达式为空,Django 将确保每个空部分首先被转换为空字符串。

用法示例

>>> # Get the display name as "name (goes_by)"
>>> from django.db.models import CharField, Value as V
>>> from django.db.models.functions import Concat
>>> Author.objects.create(name="Margaret Smith", goes_by="Maggie")
>>> author = Author.objects.annotate(
...     screen_name=Concat("name", V(" ("), "goes_by", V(")"), output_field=CharField())
... ).get()
>>> print(author.screen_name)
Margaret Smith (Maggie)

Left

class Left(expression, length, **extra)

返回给定文本字段或表达式的第一个 length 个字符。

用法示例

>>> from django.db.models.functions import Left
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(first_initial=Left("name", 1)).get()
>>> print(author.first_initial)
M

Length

class Length(expression, **extra)

接受单个文本字段或表达式,并返回该值包含的字符数。如果表达式为空,则长度也为空。

用法示例

>>> # Get the length of the name and goes_by fields
>>> from django.db.models.functions import Length
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(
...     name_length=Length("name"), goes_by_length=Length("goes_by")
... ).get()
>>> print(author.name_length, author.goes_by_length)
(14, None)

它也可以注册为转换。例如

>>> from django.db.models import CharField
>>> from django.db.models.functions import Length
>>> CharField.register_lookup(Length)
>>> # Get authors whose name is longer than 7 characters
>>> authors = Author.objects.filter(name__length__gt=7)

Lower

class Lower(expression, **extra)

接受单个文本字段或表达式,并返回小写表示形式。

它也可以注册为转换,如 Length 中所述。

用法示例

>>> from django.db.models.functions import Lower
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(name_lower=Lower("name")).get()
>>> print(author.name_lower)
margaret smith

LPad

class LPad(expression, length, fill_text=Value(' '), **extra)

返回给定文本字段或表达式的值,在左侧用 fill_text 填充,以便结果值为 length 个字符长。默认的 fill_text 是一个空格。

用法示例

>>> from django.db.models import Value
>>> from django.db.models.functions import LPad
>>> Author.objects.create(name="John", alias="j")
>>> Author.objects.update(name=LPad("name", 8, Value("abc")))
1
>>> print(Author.objects.get(alias="j").name)
abcaJohn

LTrim

class LTrim(expression, **extra)

类似于 Trim,但只删除前导空格。

MD5

class MD5(expression, **extra)

接受单个文本字段或表达式,并返回字符串的 MD5 哈希值。

它也可以注册为转换,如 Length 中所述。

用法示例

>>> from django.db.models.functions import MD5
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(name_md5=MD5("name")).get()
>>> print(author.name_md5)
749fb689816b2db85f5b169c2055b247

Ord

class Ord(expression, **extra)

接受单个文本字段或表达式,并返回该表达式第一个字符的 Unicode 代码点值。它的工作原理类似于 Python 的 ord() 函数,但如果表达式超过一个字符长,则不会引发异常。

它也可以注册为转换,如 Length 中所述。默认的查找名称是 ord

用法示例

>>> from django.db.models.functions import Ord
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(name_code_point=Ord("name")).get()
>>> print(author.name_code_point)
77

Repeat

class Repeat(expression, number, **extra)

返回给定文本字段或表达式的值,重复 number 次。

用法示例

>>> from django.db.models.functions import Repeat
>>> Author.objects.create(name="John", alias="j")
>>> Author.objects.update(name=Repeat("name", 3))
1
>>> print(Author.objects.get(alias="j").name)
JohnJohnJohn

Replace

class Replace(expression, text, replacement=Value(''), **extra)

expression 中用 replacement 替换所有出现的 text。默认的替换文本是空字符串。函数的参数区分大小写。

用法示例

>>> from django.db.models import Value
>>> from django.db.models.functions import Replace
>>> Author.objects.create(name="Margaret Johnson")
>>> Author.objects.create(name="Margaret Smith")
>>> Author.objects.update(name=Replace("name", Value("Margaret"), Value("Margareth")))
2
>>> Author.objects.values("name")
<QuerySet [{'name': 'Margareth Johnson'}, {'name': 'Margareth Smith'}]>

Reverse

class Reverse(expression, **extra)

接受单个文本字段或表达式,并以相反的顺序返回该表达式的字符。

它也可以注册为转换,如 Length 中所述。默认的查找名称是 reverse

用法示例

>>> from django.db.models.functions import Reverse
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(backward=Reverse("name")).get()
>>> print(author.backward)
htimS teragraM

Right

class Right(expression, length, **extra)

返回给定文本字段或表达式的最后 length 个字符。

用法示例

>>> from django.db.models.functions import Right
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(last_letter=Right("name", 1)).get()
>>> print(author.last_letter)
h

RPad

class RPad(expression, length, fill_text=Value(' '), **extra)

类似于 LPad,但在右侧填充。

RTrim

class RTrim(expression, **extra)

类似于 Trim,但只删除尾随空格。

SHA1SHA224SHA256SHA384SHA512

class SHA1(expression, **extra)
class SHA224(expression, **extra)
class SHA256(expression, **extra)
class SHA384(expression, **extra)
class SHA512(expression, **extra)

接受单个文本字段或表达式,并返回字符串的特定哈希值。

它们也可以像 Length 中描述的那样注册为转换。

用法示例

>>> from django.db.models.functions import SHA1
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(name_sha1=SHA1("name")).get()
>>> print(author.name_sha1)
b87efd8a6c991c390be5a68e8a7945a7851c7e5c

PostgreSQL

必须安装 pgcrypto 扩展。您可以使用 CryptoExtension 迁移操作来安装它。

Oracle

Oracle 不支持 SHA224 函数。

StrIndex

class StrIndex(string, substring, **extra)

返回一个正整数,对应于 substringstring 中第一次出现的 1 索引位置,如果未找到 substring,则返回 0。

用法示例

>>> from django.db.models import Value as V
>>> from django.db.models.functions import StrIndex
>>> Author.objects.create(name="Margaret Smith")
>>> Author.objects.create(name="Smith, Margaret")
>>> Author.objects.create(name="Margaret Jackson")
>>> Author.objects.filter(name="Margaret Jackson").annotate(
...     smith_index=StrIndex("name", V("Smith"))
... ).get().smith_index
0
>>> authors = Author.objects.annotate(smith_index=StrIndex("name", V("Smith"))).filter(
...     smith_index__gt=0
... )
<QuerySet [<Author: Margaret Smith>, <Author: Smith, Margaret>]>

警告

在 MySQL 中,数据库表的 排序规则 决定字符串比较(如此函数的 expressionsubstring)是否区分大小写。默认情况下,比较不区分大小写。

Substr

class Substr(expression, pos, length=None, **extra)

从字段或表达式中返回从位置 pos 开始的长度为 length 的子字符串。位置是 1 索引的,因此位置必须大于 0。如果 lengthNone,则将返回字符串的其余部分。

用法示例

>>> # Set the alias to the first 5 characters of the name as lowercase
>>> from django.db.models.functions import Lower, Substr
>>> Author.objects.create(name="Margaret Smith")
>>> Author.objects.update(alias=Lower(Substr("name", 1, 5)))
1
>>> print(Author.objects.get(name="Margaret Smith").alias)
marga

Trim

class Trim(expression, **extra)

返回给定文本字段或表达式的值,其中删除了前导和尾随空格。

用法示例

>>> from django.db.models.functions import Trim
>>> Author.objects.create(name="  John  ", alias="j")
>>> Author.objects.update(name=Trim("name"))
1
>>> print(Author.objects.get(alias="j").name)
John

Upper

class Upper(expression, **extra)

接受单个文本字段或表达式,并返回大写表示形式。

它也可以注册为转换,如 Length 中所述。

用法示例

>>> from django.db.models.functions import Upper
>>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(name_upper=Upper("name")).get()
>>> print(author.name_upper)
MARGARET SMITH

窗口函数

Window 表达式中使用了一些函数来计算元素的排名或某些行的 Ntile

CumeDist

class CumeDist(*expressions, **extra)

计算窗口或分区内值的累积分布。累积分布定义为在当前行之前或与当前行配对的行数除以框架中的总行数。

DenseRank

class DenseRank(*expressions, **extra)

等效于 Rank,但没有间隙。

FirstValue

class FirstValue(expression, **extra)

返回在窗口框架的第一行中计算的值,如果不存在这样的值,则返回 None

Lag

class Lag(expression, offset=1, default=None, **extra)

计算偏移量为 offset 的值,如果不存在行,则返回 default

default 必须与 expression 具有相同的类型,但是,这仅由数据库验证,而不是在 Python 中验证。

MariaDB 和 default

MariaDB 不支持 default 参数。

LastValue

class LastValue(expression, **extra)

FirstValue 相似,它计算给定框架子句中的最后一个值。

Lead

class Lead(expression, offset=1, default=None, **extra)

计算给定 框架 中的领先值。 offsetdefault 都相对于当前行进行计算。

default 必须与 expression 具有相同的类型,但是,这仅由数据库验证,而不是在 Python 中验证。

MariaDB 和 default

MariaDB 不支持 default 参数。

NthValue

class NthValue(expression, nth=1, **extra)

计算窗口内相对于偏移量 nth(必须为正值)的行。如果不存在行,则返回 None

某些数据库可能以不同的方式处理不存在的第 n 个值。例如,Oracle 返回空字符串而不是 None 用于基于字符的表达式。Django 在这些情况下不进行任何转换。

Ntile

class Ntile(num_buckets=1, **extra)

计算框架子句中每行的分区,将数字尽可能均匀地分布在 1 到 num_buckets 之间。如果行不能被桶数整除,则一个或多个桶将被更频繁地表示。

PercentRank

class PercentRank(*expressions, **extra)

计算框架子句中行的相对排名。此计算等效于评估

(rank - 1) / (total rows - 1)

下表解释了行相对排名的计算

行号 排名 计算 相对排名
1 15 1 (1-1)/(7-1) 0.0000
2 20 2 (2-1)/(7-1) 0.1666
3 20 2 (2-1)/(7-1) 0.1666
4 20 2 (2-1)/(7-1) 0.1666
5 30 5 (5-1)/(7-1) 0.6666
6 30 5 (5-1)/(7-1) 0.6666
7 40 7 (7-1)/(7-1) 1.0000

Rank

class Rank(*expressions, **extra)

RowNumber 相似,此函数对窗口中的行进行排名。计算出的排名包含间隙。使用 DenseRank 计算无间隙的排名。

RowNumber

class RowNumber(*expressions, **extra)

根据框架子句的排序或整个查询的排序(如果 窗口框架 没有分区)计算行号。

返回顶部