Spec-Zone.ru › Django 2.0

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

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

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

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

>>> # 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.
  • SQLite, Oracle и MySQL: Если какое-либо выражение является null, Greatest вернёт null.

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

Least

class Least(*expressions, **extra) [source]

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

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

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

  • PostgreSQL: Least вернёт наименьшее ненулевое выражение, или 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, может быть передан для извлечения значения в определённой часовой зоне.

Изменено в Django 2.0:

Была добавлена поддержка 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]
Новое в Django 1.11.
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
  • “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
  • “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 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]
Новое в Django 1.11:
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 округление

Новое в Django 1.11.
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

Функции текста

Concat

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

Принимает список из как минимум двух текстовых полей или выражений и возвращает конкатенированный текст. Каждый аргумент должен быть типа текст или 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)

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

StrIndex

class StrIndex(string, substring, **extra) [source]
Новая функция в Django 2.0.

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

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

Функции окна

Новая функция в Django 2.0.

Существует ряд функций для использования в выражении 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.0/ref/models/database-functions/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API