数据库函数

下面介绍的类为用户提供了一种方法,使用基础数据库提供的函数作为Django中的注释,聚合或过滤器。 函数也是expressions,因此它们可以与aggregate functions等其他表达式结合使用。

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

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)

对于CharField,我们通常不推荐允许null=True,因为这允许字段有两个“空值”,但是对于Coalesce

比较和转换函数

Cast

Cast表达式output_field[source]

强制expression的结果类型是来自output_field的结果类型。

用法示例:

>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cast
>>> Value.objects.create(integer=4)
>>> value = Value.objects.annotate(as_float=Cast('integer', FloatField())).get()
>>> print(value.as_float)
4.0

Coalesce

合并*表达式**额外[source]

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

用法示例:

>>> # Get a screen name from least to most public
>>> from django.db.models import Sum, Value as V
>>> 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
>>> aggregated = Author.objects.aggregate(
...    combined_age=Coalesce(Sum('age'), V(0)),
...    combined_age_default=Sum('age'))
>>> print(aggregated['combined_age'])
0
>>> print(aggregated['combined_age_default'])
None

警告

在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()))

Greatest

最大*表达式**额外[source]

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

用法示例:

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 will return the largest non-null expression, or null if all expressions are null.
  • SQLite,Oracle和MySQL:如果任何表达式是nullGreatest将返回null

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

Least

*表达式**额外[source]

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

警告

当一个或多个表达式可能是null时,Least

  • PostgreSQL: Least will return the smallest non-null expression, or null if all expressions are null.
  • SQLite,Oracle和MySQL:如果任何表达式为nullLeast将返回null

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

日期函数

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

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

Extract(expression, lookup_name=None, tzinfo=None, **extra)[source]

以数字形式提取日期的组成部分。

获取表示DateFieldDateTimeFieldTimeFieldDurationFieldexpression lookup_name,并将lookup_name引用的日期部分作为IntegerField返回。 Django通常使用数据库的提取函数,因此您可以使用您的数据库支持的任何lookup_name 通常由pytz提供的tzinfo子类可以被传递以提取特定时区中的值。

在Django 2.0中更改:

增加了对DurationField的支持。

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

  • “年”:2015年
  • “季度”:2
  • “月”:6
  • “日”:15
  • “周”:25
  • “week_day”:2
  • “小时”:23
  • “分”:30
  • “第二”:1

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

  • “日”:16
  • “week_day”:3
  • “小时”:9

week_day values

对于大多数数据库和Python标准函数来说,week_day lookup_type的计算方式不同。 这个函数将在星期天返回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的范围内。

Each lookup_name above has a corresponding Extract subclass (listed below) that should typically be used instead of the more verbose equivalent, e.g. use ExtractYear(...) rather than 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 extracts

ExtractYear表达式tzinfo =无**额外[source] ¶ T6>
lookup_name ='年份'
ExtractMonth(expression, tzinfo=None, **extra)[source]
lookup_name ='月'
ExtractDay表达式tzinfo =无**额外[source] ¶ T6>
lookup_name ='day'
ExtractWeekDay(expression, tzinfo=None, **extra)[source]
lookup_name ='week_day'
ExtractWeek(expression, tzinfo=None, **extra)[source]
Django 1.11新增功能
lookup_name ='week'
ExtractQuarterexpressiontzinfo = None** extra[source] ¶ T6>
Django 2.0新增功能
lookup_name ='quarter'

这些在逻辑上等同于Extract('date_field', lookup_name) Each class is also a Transform registered on DateField and DateTimeField as __(lookup_name), e.g. __year.

由于DateField没有时间分量,因此只有处理日期部分的Extract子类可以与DateField一起使用:

>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.db.models.functions import (
...     ExtractDay, ExtractMonth, ExtractQuarter, ExtractWeek,
...     ExtractWeekDay, 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'),
...     quarter=ExtractQuarter('start_date'),
...     month=ExtractMonth('start_date'),
...     week=ExtractWeek('start_date'),
...     day=ExtractDay('start_date'),
...     weekday=ExtractWeekDay('start_date'),
... ).values('year', 'quarter', 'month', 'week', 'day', 'weekday').get(
...     end_date__year=ExtractYear('start_date'),
... )
{'year': 2015, 'quarter': 2, 'month': 6, 'week': 25, 'day': 15, 'weekday': 2}

DateTimeField extracts

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

ExtractHour表达式tzinfo =无**额外[source] ¶ T6>
lookup_name ='小时'
ExtractMinute表达式tzinfo =无**额外[source] ¶ T6>
lookup_name ='分钟'
ExtractSecond(expression, tzinfo=None, **extra)[source]
lookup_name ='second'

这些在逻辑上等同于Extract('datetime_field', lookup_name) 每个类也是一个在DateTimeField上注册为__(lookup_name)Transform__minute

DateTimeField例子:

>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.db.models.functions import (
...     ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,
...     ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay,
...     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'),
...     quarter=ExtractQuarter('start_datetime'),
...     month=ExtractMonth('start_datetime'),
...     week=ExtractWeek('start_datetime'),
...     day=ExtractDay('start_datetime'),
...     weekday=ExtractWeekDay('start_datetime'),
...     hour=ExtractHour('start_datetime'),
...     minute=ExtractMinute('start_datetime'),
...     second=ExtractSecond('start_datetime'),
... ).values(
...     'year', 'month', 'week', 'day', 'weekday', 'hour', 'minute', 'second',
... ).get(end_datetime__year=ExtractYear('start_datetime'))
{'year': 2015, 'quarter': 2, 'month': 6, 'week': 25, 'day': 15, 'weekday': 2,
 'hour': 23, 'minute': 30, 'second': 1}

USE_TZTrue时,日期时间以UTC存储在数据库中。 如果在Django中有一个不同的时区处于活动状态,则在提取该值之前,日期时间将转换为该时区。 下面的示例转换为墨尔本时区(UTC +10:00),它将更改返回的星期几,星期几和小时值:

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

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

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

Now

Now[source]

返回执行查询时的数据库服务器的当前日期和时间,通常使用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

Trunc

Trunc(expression, kind, output_field=None, tzinfo=None, **extra)[source]

截断一个日期到一个重要的组件。

When you only care if something happened in a particular year, hour, or day, but not the exact second, then Trunc (and its subclasses) can be useful to filter or aggregate your data. 例如,您可以使用Trunc来计算每天的销售数量。

Trunc takes a single expression, representing a DateField, TimeField, or DateTimeField, a kind representing a date or time part, and an output_field that’s either DateTimeField(), TimeField(), or DateField(). It returns a datetime, date, or time depending on output_field, with fields up to kind set to their minimum value. 如果省略output_field,它将默认为expressionoutput_field 通常由pytz提供的tzinfo子类可以被传递以截断特定时区中的值。

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

  • “年”:2015-01-01 00:00:00 + 00:00
  • “季度”:2015-04-01 00:00:00 + 00:00
  • “月”:2015-06-01 00:00:00 + 00:00
  • “day”:2015-06-15 00:00:00 + 00:00
  • “小时”:2015-06-15 14:00:00 + 00:00
  • “分钟”:2015-06-15 14:30:00 + 00:00
  • “秒”:2015-06-15 14:30:50 + 00:00

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

  • “年”:2015-01-01 00:00:00 + 11:00
  • “季度”:2015-04-01 00:00:00 + 10:00
  • “月”:2015-06-01 00:00:00 + 10:00
  • “日”:2015-06-16 00:00:00 + 10:00
  • “小时”:2015-06-16 00:00:00 + 10:00
  • “分钟”:2015-06-16 00:30:00 + 10:00
  • “秒”:2015-06-16 00:30:50 + 10:00

由于结果转换为夏令时,因此年份的偏移量为+11:00。

Each kind above has a corresponding Trunc subclass (listed below) that should typically be used instead of the more verbose equivalent, e.g. use TruncYear(...) rather than 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截断

TruncYear(expression, output_field=None, tzinfo=None, **extra)[source]
kind ='year'
TruncMonth(expression, output_field=None, tzinfo=None, **extra)[source]
kind ='月'
TruncQuarter(expression, output_field=None, tzinfo=None, **extra)[source]
Django 2.0新增功能
kind ='quarter'

These are logically equivalent to Trunc('date_field', kind). 它们截取日期的所有部分直至kind,这允许以较低精度分组或过滤日期。 expression可以包含DateFieldDateTimeFieldoutput_field

由于DateField没有时间分量,因此只有处理日期部分的Trunc子类可以与DateField一起使用:

>>> from datetime import datetime
>>> from django.db.models import Count
>>> from django.db.models.functions import TruncMonth, TruncYear
>>> from django.utils import timezone
>>> 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 pytz
>>> melb = pytz.timezone('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截断

TruncDate(expression, **extra)[source]
lookup_name ='date'
output_field = DateField()

TruncDate casts expression to a date rather than using the built-in SQL truncate function. 它也被注册为DateTimeField的转换,如__date

TruncTime表达式**额外[source]
Django 1.11新增功能:
lookup_name ='time'
output_field = TimeField()

TruncTime casts expression to a time rather than using the built-in SQL truncate function. 它也被注册为DateTimeField的转换为__time

TruncDay(expression, output_field=None, tzinfo=None, **extra)[source]
kind ='day'
TruncHour(expression, output_field=None, tzinfo=None, **extra)[source]
kind ='小时'
TruncMinute(expression, output_field=None, tzinfo=None, **extra)[source]
kind ='分钟'
TruncSecond(expression, output_field=None, tzinfo=None, **extra)[source]
kind ='second'

These are logically equivalent to Trunc('datetime_field', kind). 它们将日期的所有部分截断为kind,并允许以较低精度对日期时间进行分组或过滤。 expression必须包含DateTimeFieldoutput_field

用法示例:

>>> from datetime import date, datetime
>>> from django.db.models import Count
>>> from django.db.models.functions import (
...     TruncDate, TruncDay, TruncHour, TruncMinute, TruncSecond,
... )
>>> from django.utils import timezone
>>> import pytz
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> melb = pytz.timezone('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=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
 'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
 'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=<UTC>),
 'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=<UTC>)
}

TimeField截断

Django 1.11新增功能
TruncHour表达式output_field =无tzinfo =无**额外[source]
kind ='小时'
TruncMinute表达式output_field =无tzinfo =无**额外[source]
kind ='分钟'
TruncSecond表达式output_field =无tzinfo =无**额外[source]
kind ='second'

These are logically equivalent to Trunc('time_field', kind). 它们将时间的所有部分截断为kind,允许以较低的精度进行分组或过滤。 expression可以包含TimeFieldDateTimeFieldoutput_field

由于TimeField没有日期分量,因此只有处理时间部分的Trunc子类可以与TimeField一起使用:

>>> from datetime import datetime
>>> from django.db.models import Count, TimeField
>>> from django.db.models.functions import TruncHour
>>> from django.utils import timezone
>>> 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 pytz
>>> melb = pytz.timezone('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

文字功能

Concat

Concat(*expressions, **extra)[source]

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

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

用法示例:

>>> # 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)

Length

长度表达式**额外[source]

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

用法示例:

>>> # 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, 'length')
>>> # Get authors whose name is longer than 7 characters
>>> authors = Author.objects.filter(name__length__gt=7)

Lower

表达式**额外[source]

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

它也可以按照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

StrIndex

StrIndex(string, substring, **extra)[source]
Django 2.0新增功能

返回对应于string中第一个出现的substring的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中,数据库表的collation确定字符串比较(例如该函数的expressionsubstring)是否区分大小写。 比较默认情况下不区分大小写。

Substr

Substr(expression, pos, length=None, **extra)[source]

从位置pos开始的字段或表达式返回长度length的子字符串。 该位置是1索引的,所以位置必须大于0。 如果lengthNone,那么字符串的其余部分将被返回。

用法示例:

>>> # Set the alias to the first 5 characters of the name as lowercase
>>> from django.db.models.functions import Substr, Lower
>>> 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

Upper

上面表达式**额外[source]

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

它也可以按照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

窗口函数

Django 2.0新增功能

Window表达式中有许多函数用于计算某些行的元素或者Ntile的排名。

CumeDist

CumeDist*表达式**额外[source]

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

DenseRank

DenseRank*表达式**额外[source]

相当于Rank,但没有差距。

FirstValue

FirstValue(expression, **extra)[source]

返回在窗口框架的第一行所评估的值,如果不存在这样的值,则返回None

Lag

Lag(expression, offset=1, default=None, **extra)[source]

通过offset计算值偏移量,如果没有行存在,则返回default

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

LastValue

LastValue(expression, **extra)[source]

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

Lead

Lead(expression, offset=1, default=None, **extra)[source]

计算给定frame中的前导值。 根据当前行计算offsetdefault

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

NthValue

NthValue(expression, nth=1, **extra)[source]

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

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

Ntile

Ntilenum_buckets = 1** extra[source]

计算frame子句中每一行的分区,尽可能均匀地在1到num_buckets之间分配数字。 如果行不能平均分配到多个桶中,则会更频繁地表示一个或多个桶。

PercentRank

PercentRank*表达式**额外[source]

计算框架子句中行的百分比等级。 这个计算等同于评估:

(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

Rank*表达式**额外[source]

RowNumber类似,这个函数对窗口中的行进行排序。 计算的等级包含差距。 使用DenseRank计算没有间隙的排名。

RowNumber

RowNumber(*expressions, **extra)[source]

如果没有对window frame进行分区,则根据框架子句的排序或整个查询的排序计算行号。