Функции базы данных
Приведенные ниже классы позволяют пользователям использовать функции, предоставляемые основной базой данных, в качестве аннотаций, агрегаций или фильтров в 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)[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
-
class Coalesce(*expressions, **extra)[source]
Принимает список из как минимум двух имен полей или выражений и возвращает первое не-null значение (обратите внимание, что пустая строка не считается null-значением). Каждый аргумент должен быть одного типа, поэтому смешивание текста и чисел приведёт к ошибке базы данных.
Примеры использования:
>>> # 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
Предупреждение
Значение 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()))
Greatest
-
class Greatest(*expressions, **extra)[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.modified и comment.modified.
Предупреждение
Поведение Greatest в случае, если одно или несколько выражений могут быть null различается в разных базах данных:
- PostgreSQL:
Greatestвернёт наибольшее не-null выражение илиnull, если все выражения являютсяnull. - SQLite, Oracle и MySQL: Если какое-либо выражение является
null,Greatestвернётnull.
Поведение PostgreSQL можно эмулировать с помощью Coalesce, если вы знаете разумное минимальное значение, чтобы использовать в качестве значения по умолчанию.
Least
-
class Least(*expressions, **extra)[source]
Принимает список из как минимум двух имен полей или выражений и возвращает наименьшее значение. Каждый аргумент должен быть одного типа, поэтому смешивание текста и чисел приведёт к ошибке базы данных.
Предупреждение
Поведение Least в случае, если одно или несколько выражений могут быть null различается в разных базах данных:
- PostgreSQL:
Leastвернёт наименьшее не-null выражение илиnull, если все выражения являютсяnull. - SQLite, Oracle и MySQL: Если какое-либо выражение является
null,Leastвернётnull.
Поведение PostgreSQL можно эмулировать с помощью Coalesce, если вы знаете разумное максимальное значение, чтобы использовать в качестве значения по умолчанию.
Функции даты
В примерах каждой функции мы будем использовать следующую модель:
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)[source]
Извлекает компонент даты в виде числа.
Принимает expression представляющий DateField, DateTimeField, TimeField, или DurationField и lookup_name, и возвращает часть даты, на которую ссылается lookup_name в качестве IntegerField. Django обычно использует функцию извлечения базы данных, поэтому вы можете использовать любые lookup_name поддерживаемые вашей базой данных. Класс, наследуемый от tzinfo, обычно предоставляемый pytz, может быть передан для извлечения значения в определённой временной зоне.
Добавлена поддержка DurationField.
Для даты-времени 2015-06-15 23:30:01.000321+00:00 встроенные функции lookup_name возвращают:
- “year”: 2015
- “quarter”: 2
- “month”: 6
- “day”: 15
- “week”: 25
- “week_day”: 2
- “hour”: 23
- “minute”: 30
- “second”: 1
Если в Django активна другая временная зона, например, Australia/Melbourne, то дата-время преобразуется в эту временную зону до извлечения значения. Смещение временной зоны для Мельбурна в примере даты выше составляет +10:00. Значения, возвращаемые при активации этой временной зоны, будут такими же, как и выше, за исключением:
- “day”: 16
- “week_day”: 3
- “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 значения
Значение 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)[source] -
-
lookup_name = 'year'
-
-
class ExtractMonth(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'month'
-
-
class ExtractDay(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'day'
-
-
class ExtractWeekDay(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'week_day'
-
-
class ExtractWeek(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'week'
-
-
class ExtractQuarter(expression, tzinfo=None, **extra)[source] -
Новое в Django 2.0.
-
lookup_name = 'quarter'
-
Эти классы логически эквивалентны Extract('date_field', lookup_name). Каждый класс также является Transform зарегистрированным в DateField и DateTimeField в качестве __(lookup_name), например, __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 извлечения
В дополнение к этому, все извлечения для DateField указанные выше, также могут использоваться с DateTimeField.
-
class ExtractHour(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'hour'
-
-
class ExtractMinute(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'minute'
-
-
class ExtractSecond(expression, tzinfo=None, **extra)[source] -
-
lookup_name = 'second'
-
Эти логически эквивалентны Extract('datetime_field', lookup_name). Каждый класс также является Transform зарегистрированным на DateTimeField как __(lookup_name), например, __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_TZ равно True, значения datetime хранятся в базе данных в формате UTC. Если в Django активен другой часовой пояс, datetime преобразуется в этот часовой пояс перед извлечением значения. Приведенный ниже пример преобразует значение в часовой пояс Мельбурна (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
-
class 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
-
class Trunc(expression, kind, output_field=None, tzinfo=None, **extra)[source]
Округляет дату до значимого компонента.
Когда вас интересует только то, произошло ли что-то в конкретном году, часу или дне, а не точная секунда, тогда Trunc (и его подклассы) могут быть полезны для фильтрации или агрегирования ваших данных. Например, вы можете использовать Trunc для подсчета числа продаж в день.
Trunc принимает один expression, представляющий DateField, TimeField или DateTimeField, kind представляющий часть даты или времени, и output_field, который может быть DateTimeField(), TimeField() или DateField(). Возвращает datetime, date или time в зависимости от output_field, с полями до kind установленных в минимальное значение. Если output_field опущено, по умолчанию используется output_field expression. Можно передать подкласс tzinfo, обычно предоставляемый pytz, чтобы округлить значение в определенном часовом поясе.
Для datetime 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, datetime преобразуется в новый часовой пояс перед округлением. Смещение часового пояса для Мельбурна в примере даты выше +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)[source] -
-
kind = 'year'
-
-
class TruncMonth(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'month'
-
-
class TruncWeek(expression, output_field=None, tzinfo=None, **extra)[source] -
Добавлена в Django 2.1.
Округляет до полуночи в понедельник недели.
-
kind = 'week'
-
-
class TruncQuarter(expression, output_field=None, tzinfo=None, **extra)[source] -
Добавлена в Django 2.0.
-
kind = 'quarter'
-
Эти логически эквивалентны Trunc('date_field', kind). Они округляют все части даты до kind, что позволяет группировать или фильтровать даты с меньшей точностью. expression может иметь output_field DateField или DateTimeField.
Так как 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 округление
-
class TruncDate(expression, **extra)[source] -
-
lookup_name = 'date'
-
output_field = DateField()
-
TruncDate преобразует expression в дату, а не используя встроенную SQL-функцию округления. Он также зарегистрирован как преобразование в DateTimeField как __date.
-
class TruncTime(expression, **extra)[source] -
-
lookup_name = 'time'
-
output_field = TimeField()
-
TruncTime преобразует expression в время, а не используя встроенную SQL-функцию округления. Он также зарегистрирован как преобразование в DateTimeField как __time.
-
class TruncDay(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'day'
-
-
class TruncHour(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'hour'
-
-
class TruncMinute(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'minute'
-
-
class TruncSecond(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'second'
-
Эти логически эквивалентны Trunc('datetime_field', kind). Они округляют все части даты до kind и позволяют группировать или фильтровать datetime с меньшей точностью. expression должно иметь output_field DateTimeField.
Пример использования:
>>> 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 округление
-
class TruncHour(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'hour'
-
-
class TruncMinute(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'minute'
-
-
class TruncSecond(expression, output_field=None, tzinfo=None, **extra)[source] -
-
kind = 'second'
-
Эти логически эквивалентны Trunc('time_field', kind). Они округляют все части времени до kind, что позволяет группировать или фильтровать время с меньшей точностью. expression должно иметь output_field TimeField или DateTimeField.
Так как 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
Функции текста
Chr
-
class Chr(expression, **extra)[source]
Принимает числовое поле или выражение и возвращает текстовое представление выражения как одиночного символа. Работает так же, как функция 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)[source]
Принимает список из как минимум двух текстовых полей или выражений и возвращает конкатенированный текст. Каждый аргумент должен быть типа text или char. Если вы хотите конкатенировать TextField() с CharField(), убедитесь, что указали Django, что output_field должен быть типа TextField(). Указание типа output_field также необходимо при конкатенации Value, как в примере ниже.
Функция никогда не возвращает null-значение. В базах данных, где null-аргумент приводит к 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)
Left
-
class Left(expression, length, **extra)[source]
Возвращает первые 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)[source]
Принимает одно текстовое поле или выражение и возвращает количество символов в значении. Если выражение равно 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)[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
LPad
-
class LPad(expression, length, fill_text=Value(' '), **extra)[source]
Возвращает значение заданного текстового поля или выражения, дополненного слева 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)[source]
Аналогично Trim, но удаляет только начальные пробелы.
Ord
-
class Ord(expression, **extra)[source]
Принимает одно текстовое поле или выражение и возвращает значение кода Юникода первого символа этого выражения. Похоже на функцию 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)[source]
Возвращает значение заданного текстового поля или выражения, повторённое 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)[source]
Заменяет все вхождения 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'}]>
Right
-
class Right(expression, length, **extra)[source]
Возвращает последние 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)[source]
Аналогично LPad, но добавляет символы справа.
RTrim
-
class RTrim(expression, **extra)[source]
Аналогично Trim, но удаляет только конечные пробелы.
StrIndex
-
class StrIndex(string, substring, **extra)[source]
Возвращает целое положительное число, соответствующее индексу (с учётом нумерации с 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)[source]
Возвращает подстроку длиной 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)[source]
Возвращает значение заданного текстового поля или выражения с удалёнными начальными и конечными пробелами.
Пример использования:
>>> 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)[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
Функции окон
Существует ряд функций, которые можно использовать в выражении Window для вычисления ранга элементов или Ntile некоторых строк.
CumeDist
-
class CumeDist(*expressions, **extra)[source]
Вычисляет кумулятивное распределение значения в окне или разбиении. Кумулятивное распределение определяется как количество строк, предшествующих или сопоставленных с текущей строкой, деленное на общее количество строк в фрагменте.
DenseRank
-
class DenseRank(*expressions, **extra)[source]
Эквивалентно Rank, но без разрывов.
FirstValue
-
class FirstValue(expression, **extra)[source]
Возвращает значение, вычисленное в строке, которая является первой строкой в окне фрагмента, или None если такой строки нет.
Lag
-
class Lag(expression, offset=1, default=None, **extra)[source]
Вычисляет значение, смещенное на offset, и если такой строки нет, возвращает default.
default должно иметь тот же тип, что и expression, однако это проверяется только базой данных, а не в Python.
LastValue
-
class LastValue(expression, **extra)[source]
Аналогично FirstValue, вычисляет последнее значение в данном фрагменте.
Lead
-
class Lead(expression, offset=1, default=None, **extra)[source]
Вычисляет ведущее значение в данном фрагменте. Оба offset и default вычисляются относительно текущей строки.
default должно иметь тот же тип, что и expression, однако это проверяется только базой данных, а не в Python.
NthValue
-
class NthValue(expression, nth=1, **extra)[source]
Вычисляет строку, относящуюся к смещению nth (должно быть положительным значением) в окне. Возвращает None если такой строки нет.
Некоторые базы данных могут по-разному обрабатывать несуществующее n-е значение. Например, Oracle возвращает пустую строку вместо None для выражений на основе символов. Django не выполняет никаких преобразований в этих случаях.
Ntile
-
class Ntile(num_buckets=1, **extra)[source]
Вычисляет разбиение для каждой строки во фрагменте, распределяя числа как можно равномернее между 1 и num_buckets. Если строки не делятся равномерно на количество корзинок, одна или несколько корзинок будут представлены чаще.
PercentRank
-
class PercentRank(*expressions, **extra)[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
-
class Rank(*expressions, **extra)[source]
Аналогично RowNumber, эта функция ранжирует строки в окне. Вычисленный ранг содержит разрывы. Используйте DenseRank для вычисления ранга без разрывов.
RowNumber
-
class RowNumber(*expressions, **extra)[source]
Вычисляет номер строки в соответствии с порядком либо фрагмента, либо всего запроса, если нет разбиения окна фрагмента.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.1/ref/models/database-functions/