Функции базы данных

Классы, описанные ниже, предоставляют пользователям возможность использовать функции, предоставляемые базой данных, в качестве аннотаций, агрегаций или фильтров в 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)

Обычно мы не рекомендуем разрешать 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

Предупреждение

Значение Python, переданное в Coalesce на MySQL, может быть преобразовано к неправильному типу, если явно не привести его к правильному типу базы данных:

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

Принимает выражение и имя 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.modified и comment.modified.

Предупреждение

Поведение Greatest, когда одно или несколько выражений могут быть null, варьируется между базами данных:

  • PostgreSQL: Greatest вернет наибольшее ненулевое выражение, или null, если все выражения равны null.
  • SQLite, Oracle и MySQL: Если какое-либо выражение равно null, Greatest вернет null.

Поведение PostgreSQL можно эмулировать с помощью Coalesce, если вы знаете разумное минимальное значение по умолчанию.

Least

class Least(*expressions, **extra)

Принимает список из не менее двух имен полей или выражений и возвращает наименьшее значение. Каждый аргумент должен быть одинакового типа, поэтому смешивание текста и чисел приведет к ошибке базы данных.

Предупреждение

Поведение Least, когда одно или несколько выражений могут быть null, варьируется между базами данных:

  • PostgreSQL: Least вернет наименьшее ненулевое выражение, или null, если все выражения равны null.
  • SQLite, Oracle и MySQL: Если какое-либо выражение равно null, Least вернет null.

Поведение PostgreSQL можно эмулировать с помощью Coalesce, если вы знаете разумное максимальное значение по умолчанию.

NullIf

class NullIf(expression1, expression2)

Принимает два выражения и возвращает None, если они равны, в противном случае возвращает expression1.

Предостережения относительно Oracle

Из-за ошибки Oracle convention эта функция возвращает пустую строку вместо None, когда выражения имеют тип CharField.

Передача Value(None) в expression1 запрещена в Oracle, поскольку Oracle не принимает NULL в качестве первого аргумента.

Функции даты

В примерах каждой функции мы будем использовать следующую модель:

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)

Извлекает компонент даты в виде числа.

Принимает expression, представляющий DateField, DateTimeField, TimeField или DurationField и lookup_name, и возвращает часть даты, на которую ссылается lookup_name в виде IntegerField. Django обычно использует функцию извлечения баз данных, поэтому вы можете использовать любые lookup_name, которые поддерживает ваша база данных. Подкласс tzinfo, обычно предоставляемый zoneinfo, может быть передан для извлечения значения в определенном часовом поясе.

Учитывая время даты 2015-06-15 23:30:01.000321+00:00, встроенные lookup_names возвращаются:

  • «год»: 2015
  • «iso_year»: 2015
  • «квартал»: 2
  • «месяц»: 6
  • «день»: 15
  • «неделя»: 25
  • «week_day»: 2
  • «iso_week_day»: 1
  • «час»: 23
  • «минута»: 30
  • «second»: 1

Если в Django активен другой часовой пояс, например Australia/Melbourne, то перед извлечением значения дататайм преобразуется в часовой пояс. Смещение часового пояса для Мельбурна в приведенном выше примере даты составляет +10:00. Значения, возвращаемые при активном часовом поясе, будут такими же, как и выше, за исключением:

  • «день»: 16
  • «week_day»: 3
  • «iso_week_day»: 2
  • «час»: 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 значения

Неделя week lookup_type рассчитывается на основе ISO-8601, т.е. неделя начинается в понедельник. Первая неделя года - это та, которая содержит первый четверг года, т.е. первая неделя имеет большинство (четыре или более) дней в году. Возвращаемое значение находится в диапазоне от 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). Каждый класс также является Transform, зарегистрированным на DateField и DateTimeField как __(lookup_name), например, __year.

Поскольку DateFieldне имеет компонента времени, с DateField можно использовать только подклассы Extract, работающие с компонентами даты:

>>> 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 могут быть использованы и для DateTimeFields .

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). Каждый класс также является Transform, зарегистрированным на DateTimeField как __(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_TZ имеет значение True, то даты хранятся в базе данных в формате 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.

Trunc

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

Усекает дату до значимого компонента.

Если вам важно, произошло ли что-то в определенный год, час или день, но не в точную секунду, то Trunc (и его подклассы) могут быть полезны для фильтрации или агрегации данных. Например, вы можете использовать Trunc для подсчета количества продаж в день.

Trunc принимает один expression, представляющий DateField, TimeField или DateTimeField, kind, представляющий часть даты или времени, и output_field, который является либо DateTimeField(), либо TimeField(), либо DateField(). Он возвращает время, дату или время в зависимости от output_field, при этом поля до kind устанавливаются в минимальное значение. Если output_field опущено, то по умолчанию будет возвращено output_field из expression. Подкласс tzinfo, обычно предоставляемый zoneinfo, может быть передан для усечения значения в определенном часовом поясе.

Учитывая время даты 2015-06-15 14:30:50.000321+00:00, встроенные kinds возвращаются:

  • «год»: 2015-01-01 00:00:00+00:00
  • «квартал»: 2015-04-01 00:00:00+00:00
  • «месяц»: 2015-06-01 00:00:00+00:00
  • «неделя»: 2015-06-15 00:00:00+00:00
  • «день»: 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

Если в Django активен другой часовой пояс, например Australia/Melbourne, то дататайм конвертируется в новый часовой пояс перед усечением значения. Смещение часового пояса для Мельбурна в приведенном выше примере даты составляет +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:00:00+10:00
  • «минута»: 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 может иметь output_field либо DateField, либо DateTimeField.

Поскольку DateFieldне имеет компонента времени, с DateField можно использовать только подклассы Trunc, работающие с компонентами даты:

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

TruncDate приводит expression к дате вместо того, чтобы использовать встроенную функцию SQL truncate. Она также зарегистрирована как преобразование DateTimeField в __date.

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

TruncTime приводит expression к времени, а не использует встроенную функцию SQL truncate. Она также зарегистрирована как преобразование DateTimeField в __time.

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 должен иметь output_field из DateTimeField.

Пример использования:

>>> 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 либо TimeField, либо DateTimeField.

Поскольку TimeFieldне имеет компонента даты, с TimeField можно использовать только подклассы Trunc, работающие с временными частями:

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

Функции JSON

JSONArray

New in Django 5.2.
class JSONArray(*expressions)

Принимает список имен полей или выражений и возвращает массив JSON, содержащий эти значения.

Пример использования:

>>> from django.db.models import F
>>> from django.db.models.functions import JSONArray, Lower
>>> Author.objects.create(name="Margaret Smith", alias="msmith", age=25)
>>> author = Author.objects.annotate(
...     json_array=JSONArray(
...         Lower("name"),
...         "alias",
...         F("age") * 2,
...     )
... ).get()
>>> author.json_array
['margaret smith', 'msmith', 50]

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}

Математические функции

В примерах математических функций мы будем использовать следующую модель:

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)

Принимает два числовых поля или выражения и возвращает остаток от деления первого на второе (операция modulo).

Пример использования:

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

Принимает список из как минимум двух текстовых полей или выражений и возвращает конкатенированный текст. Каждый аргумент должен иметь тип text или char. Если вы хотите объединить TextField() с CharField(), то не забудьте указать Django, что output_field должно быть TextField(). Указание output_field также необходимо при конкатенации Value, как в примере ниже.

Эта функция никогда не будет иметь нулевого результата. На бэкендах, где нулевой аргумент приводит к тому, что все выражение становится нулевым, 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)

Принимает одно текстовое поле или выражение и возвращает количество символов в значении. Если выражение равно null, то длина также будет равна null.

Пример использования:

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

Заменяет все вхождения text на replacement в expression. Текст замены по умолчанию - пустая строка. Аргументы функции чувствительны к регистру.

Пример использования:

>>> 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, но удаляет только пробелы в конце строки.

SHA1, SHA224, SHA256, SHA384 и SHA512

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 extension. Для его установки можно использовать операцию миграции CryptoExtension.

Oracle

Oracle не поддерживает функцию SHA224.

StrIndex

class StrIndex(string, substring, **extra)

Возвращает положительное целое число, соответствующее 1-индексированной позиции первого вхождения substring внутри string, или 0, если substring не найдено.

Пример использования:

>>> 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 таблицы базы данных определяет, являются ли сравнения строк (такие как expression и substring этой функции) чувствительными к регистру. По умолчанию сравнения не чувствительны к регистру.

Substr

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

Возвращает подстроку длины length из поля или выражения, начиная с позиции pos. Позиция индексируется по 1, поэтому позиция должна быть больше 0. Если length будет None, то будет возвращена остальная часть строки.

Пример использования:

>>> # 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 doesn’t support параметр default.

LastValue

class LastValue(expression, **extra)

Сравнимо с FirstValue, вычисляет последнее значение в данном фрейме.

Lead

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

Вычисляет ведущее значение в заданном frame. И offset, и default оцениваются относительно текущей строки.

default должен иметь тот же тип, что и expression, однако это проверяется только в базе данных, а не в Python.

MariaDB и default

MariaDB doesn’t support параметр default.

NthValue

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

Вычисляет строку относительно смещения nth (должно быть положительное значение) в пределах окна. Возвращает None, если ряд не существует.

Некоторые базы данных могут по-разному обрабатывать несуществующее n-ое значение. Например, Oracle возвращает пустую строку, а не None для выражений на основе символов. Django не делает никаких преобразований в этих случаях.

Ntile

class Ntile(num_buckets=1, **extra)

Вычисляет раздел для каждой из строк в предложении frame, распределяя числа как можно более равномерно между 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)

Вычисляет номер строки в соответствии с упорядочиванием либо клаузулы frame, либо упорядочиванием всего запроса, если нет разбиения window frame.

Вернуться на верх