From eabcf85b6feae54aea6ef1fd307b66b6c7b5c9af Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Tue, 10 Oct 2017 19:52:07 +0200 Subject: [PATCH] Refs #28643 -- Reorganized database functions docs and moved text functions to a separate file. --- django/db/models/functions/__init__.py | 13 +- django/db/models/functions/misc.py | 96 +++++ .../db/models/functions/{base.py => text.py} | 96 +---- docs/ref/models/database-functions.txt | 401 +++++++++--------- docs/releases/1.10.txt | 14 +- docs/releases/1.11.txt | 12 +- docs/releases/2.0.txt | 10 +- 7 files changed, 324 insertions(+), 318 deletions(-) create mode 100644 django/db/models/functions/misc.py rename django/db/models/functions/{base.py => text.py} (51%) diff --git a/django/db/models/functions/__init__.py b/django/db/models/functions/__init__.py index aab74b232adbf..a7fdb92b8dd2e 100644 --- a/django/db/models/functions/__init__.py +++ b/django/db/models/functions/__init__.py @@ -1,22 +1,21 @@ -from .base import ( - Cast, Coalesce, Concat, ConcatPair, Greatest, Least, Length, Lower, Now, - StrIndex, Substr, Upper, -) from .datetime import ( Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek, ExtractWeekDay, ExtractYear, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncYear, ) +from .misc import Cast, Coalesce, Greatest, Least, Now +from .text import Concat, ConcatPair, Length, Lower, StrIndex, Substr, Upper from .window import ( CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile, PercentRank, Rank, RowNumber, ) __all__ = [ - # base - 'Cast', 'Coalesce', 'Concat', 'ConcatPair', 'Greatest', 'Least', 'Length', - 'Lower', 'Now', 'StrIndex', 'Substr', 'Upper', + # misc + 'Cast', 'Coalesce', 'Greatest', 'Least', 'Now', + # text + 'Concat', 'ConcatPair', 'Length', 'Lower', 'StrIndex', 'Substr', 'Upper', # datetime 'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth', 'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractWeekDay', diff --git a/django/db/models/functions/misc.py b/django/db/models/functions/misc.py new file mode 100644 index 0000000000000..434fea0d826dc --- /dev/null +++ b/django/db/models/functions/misc.py @@ -0,0 +1,96 @@ +""" +Classes that represent database functions. +""" +from django.db.models import Func, fields + + +class Cast(Func): + """Coerce an expression to a new field type.""" + function = 'CAST' + template = '%(function)s(%(expressions)s AS %(db_type)s)' + + def __init__(self, expression, output_field): + super().__init__(expression, output_field=output_field) + + def as_sql(self, compiler, connection, **extra_context): + extra_context['db_type'] = self.output_field.cast_db_type(connection) + return super().as_sql(compiler, connection, **extra_context) + + def as_postgresql(self, compiler, connection): + # CAST would be valid too, but the :: shortcut syntax is more readable. + return self.as_sql(compiler, connection, template='%(expressions)s::%(db_type)s') + + +class Coalesce(Func): + """Return, from left to right, the first non-null expression.""" + function = 'COALESCE' + + def __init__(self, *expressions, **extra): + if len(expressions) < 2: + raise ValueError('Coalesce must take at least two expressions') + super().__init__(*expressions, **extra) + + def as_oracle(self, compiler, connection): + # we can't mix TextField (NCLOB) and CharField (NVARCHAR), so convert + # all fields to NCLOB when we expect NCLOB + if self.output_field.get_internal_type() == 'TextField': + class ToNCLOB(Func): + function = 'TO_NCLOB' + + expressions = [ + ToNCLOB(expression) for expression in self.get_source_expressions()] + clone = self.copy() + clone.set_source_expressions(expressions) + return super(Coalesce, clone).as_sql(compiler, connection) + return self.as_sql(compiler, connection) + + +class Greatest(Func): + """ + Return the maximum expression. + + If any expression is null the return value is database-specific: + On Postgres, the maximum not-null expression is returned. + On MySQL, Oracle, and SQLite, if any expression is null, null is returned. + """ + function = 'GREATEST' + + def __init__(self, *expressions, **extra): + if len(expressions) < 2: + raise ValueError('Greatest must take at least two expressions') + super().__init__(*expressions, **extra) + + def as_sqlite(self, compiler, connection): + """Use the MAX function on SQLite.""" + return super().as_sqlite(compiler, connection, function='MAX') + + +class Least(Func): + """ + Return the minimum expression. + + If any expression is null the return value is database-specific: + On Postgres, return the minimum not-null expression. + On MySQL, Oracle, and SQLite, if any expression is null, return null. + """ + function = 'LEAST' + + def __init__(self, *expressions, **extra): + if len(expressions) < 2: + raise ValueError('Least must take at least two expressions') + super().__init__(*expressions, **extra) + + def as_sqlite(self, compiler, connection): + """Use the MIN function on SQLite.""" + return super().as_sqlite(compiler, connection, function='MIN') + + +class Now(Func): + template = 'CURRENT_TIMESTAMP' + output_field = fields.DateTimeField() + + def as_postgresql(self, compiler, connection): + # Postgres' CURRENT_TIMESTAMP means "the time at the start of the + # transaction". We use STATEMENT_TIMESTAMP to be cross-compatible with + # other databases. + return self.as_sql(compiler, connection, template='STATEMENT_TIMESTAMP()') diff --git a/django/db/models/functions/base.py b/django/db/models/functions/text.py similarity index 51% rename from django/db/models/functions/base.py rename to django/db/models/functions/text.py index 4b4d4f4ea5fdd..4ec07be2dfc06 100644 --- a/django/db/models/functions/base.py +++ b/django/db/models/functions/text.py @@ -1,48 +1,5 @@ -""" -Classes that represent database functions. -""" from django.db.models import Func, Transform, Value, fields - - -class Cast(Func): - """Coerce an expression to a new field type.""" - function = 'CAST' - template = '%(function)s(%(expressions)s AS %(db_type)s)' - - def __init__(self, expression, output_field): - super().__init__(expression, output_field=output_field) - - def as_sql(self, compiler, connection, **extra_context): - extra_context['db_type'] = self.output_field.cast_db_type(connection) - return super().as_sql(compiler, connection, **extra_context) - - def as_postgresql(self, compiler, connection): - # CAST would be valid too, but the :: shortcut syntax is more readable. - return self.as_sql(compiler, connection, template='%(expressions)s::%(db_type)s') - - -class Coalesce(Func): - """Return, from left to right, the first non-null expression.""" - function = 'COALESCE' - - def __init__(self, *expressions, **extra): - if len(expressions) < 2: - raise ValueError('Coalesce must take at least two expressions') - super().__init__(*expressions, **extra) - - def as_oracle(self, compiler, connection): - # we can't mix TextField (NCLOB) and CharField (NVARCHAR), so convert - # all fields to NCLOB when we expect NCLOB - if self.output_field.get_internal_type() == 'TextField': - class ToNCLOB(Func): - function = 'TO_NCLOB' - - expressions = [ - ToNCLOB(expression) for expression in self.get_source_expressions()] - clone = self.copy() - clone.set_source_expressions(expressions) - return super(Coalesce, clone).as_sql(compiler, connection) - return self.as_sql(compiler, connection) +from django.db.models.functions import Coalesce class ConcatPair(Func): @@ -98,46 +55,6 @@ def _paired(self, expressions): return ConcatPair(expressions[0], self._paired(expressions[1:])) -class Greatest(Func): - """ - Return the maximum expression. - - If any expression is null the return value is database-specific: - On Postgres, the maximum not-null expression is returned. - On MySQL, Oracle, and SQLite, if any expression is null, null is returned. - """ - function = 'GREATEST' - - def __init__(self, *expressions, **extra): - if len(expressions) < 2: - raise ValueError('Greatest must take at least two expressions') - super().__init__(*expressions, **extra) - - def as_sqlite(self, compiler, connection): - """Use the MAX function on SQLite.""" - return super().as_sqlite(compiler, connection, function='MAX') - - -class Least(Func): - """ - Return the minimum expression. - - If any expression is null the return value is database-specific: - On Postgres, return the minimum not-null expression. - On MySQL, Oracle, and SQLite, if any expression is null, return null. - """ - function = 'LEAST' - - def __init__(self, *expressions, **extra): - if len(expressions) < 2: - raise ValueError('Least must take at least two expressions') - super().__init__(*expressions, **extra) - - def as_sqlite(self, compiler, connection): - """Use the MIN function on SQLite.""" - return super().as_sqlite(compiler, connection, function='MIN') - - class Length(Transform): """Return the number of characters in the expression.""" function = 'LENGTH' @@ -153,17 +70,6 @@ class Lower(Transform): lookup_name = 'lower' -class Now(Func): - template = 'CURRENT_TIMESTAMP' - output_field = fields.DateTimeField() - - def as_postgresql(self, compiler, connection): - # Postgres' CURRENT_TIMESTAMP means "the time at the start of the - # transaction". We use STATEMENT_TIMESTAMP to be cross-compatible with - # other databases. - return self.as_sql(compiler, connection, template='STATEMENT_TIMESTAMP()') - - class StrIndex(Func): """ Return a positive integer corresponding to the 1-indexed position of the diff --git a/docs/ref/models/database-functions.txt b/docs/ref/models/database-functions.txt index 5b0c77aa9ea52..779e4fbcc8ba7 100644 --- a/docs/ref/models/database-functions.txt +++ b/docs/ref/models/database-functions.txt @@ -80,37 +80,6 @@ Usage examples:: >>> now = timezone.now() >>> Coalesce('updated', Cast(now, DateTimeField())) -``Concat`` -========== - -.. class:: Concat(*expressions, **extra) - -Accepts a list of at least two text fields or expressions and returns the -concatenated text. Each argument must be of a text or char type. If you want -to concatenate a ``TextField()`` with a ``CharField()``, then be sure to tell -Django that the ``output_field`` should be a ``TextField()``. Specifying an -``output_field`` is also required when concatenating a ``Value`` as in the -example below. - -This function will never have a null result. On backends where a null argument -results in the entire expression being null, Django will ensure that each null -part is converted to an empty string first. - -Usage example:: - - >>> # 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) - ``Greatest`` ============ @@ -175,51 +144,6 @@ will result in a database error. The PostgreSQL behavior can be emulated using ``Coalesce`` if you know a sensible maximum value to provide as a default. -``Length`` -========== - -.. class:: Length(expression, **extra) - -Accepts a single text field or expression and returns the number of characters -the value has. If the expression is null, then the length will also be null. - -Usage example:: - - >>> # 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) - -It can also be registered as a transform. For example:: - - >>> 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) - -Accepts a single text field or expression and returns the lowercase -representation. - -It can also be registered as a transform as described in :class:`Length`. - -Usage example:: - - >>> 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 - ``Now`` ======= @@ -241,82 +165,11 @@ Usage example:: ``Now()`` uses ``STATEMENT_TIMESTAMP`` instead. If you need the transaction timestamp, use :class:`django.contrib.postgres.functions.TransactionNow`. -``StrIndex`` -============ - -.. class:: StrIndex(string, substring, **extra) - -.. versionadded:: 2.0 - -Returns a positive integer corresponding to the 1-indexed position of the first -occurrence of ``substring`` inside ``string``, or 0 if ``substring`` is not -found. - -Usage example:: - - >>> 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) - , ]> - -.. warning:: - - In MySQL, a database table's :ref:`collation` determines - whether string comparisons (such as the ``expression`` and ``substring`` of - this function) are case-sensitive. Comparisons are case-insensitive by - default. - -``Substr`` -========== - -.. class:: Substr(expression, pos, length=None, **extra) - -Returns a substring of length ``length`` from the field or expression starting -at position ``pos``. The position is 1-indexed, so the position must be greater -than 0. If ``length`` is ``None``, then the rest of the string will be returned. - -Usage example:: - - >>> # Set the alias to the first 5 characters of the name as lowercase - >>> from django.db.models.functions import Substr, Lower - >>> Author.objects.create(name='Margaret Smith') - >>> Author.objects.update(alias=Lower(Substr('name', 1, 5))) - 1 - >>> print(Author.objects.get(name='Margaret Smith').alias) - marga - -``Upper`` -========= - -.. class:: Upper(expression, **extra) - -Accepts a single text field or expression and returns the uppercase -representation. - -It can also be registered as a transform as described in :class:`Length`. - -Usage example:: - - >>> 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 +.. _date-functions: Date Functions ============== -.. module:: django.db.models.functions.datetime - We'll be using the following model in examples of each function:: class Experiment(models.Model): @@ -692,6 +545,74 @@ that deal with date-parts can be used with ``DateField``:: 2016-01-01 00:00:00+11:00 1 2014-06-01 00:00:00+10:00 1 +``DateTimeField`` truncation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: TruncDate(expression, **extra) + + .. attribute:: lookup_name = 'date' + .. attribute:: output_field = DateField() + +``TruncDate`` casts ``expression`` to a date rather than using the built-in SQL +truncate function. It's also registered as a transform on ``DateTimeField`` as +``__date``. + +.. class:: TruncTime(expression, **extra) + + .. attribute:: lookup_name = 'time' + .. attribute:: output_field = TimeField() + +``TruncTime`` casts ``expression`` to a time rather than using the built-in SQL +truncate function. It's also registered as a transform on ``DateTimeField`` as +``__time``. + +.. class:: TruncDay(expression, output_field=None, tzinfo=None, **extra) + + .. attribute:: kind = 'day' + +.. class:: TruncHour(expression, output_field=None, tzinfo=None, **extra) + + .. attribute:: kind = 'hour' + +.. class:: TruncMinute(expression, output_field=None, tzinfo=None, **extra) + + .. attribute:: kind = 'minute' + +.. class:: TruncSecond(expression, output_field=None, tzinfo=None, **extra) + + .. attribute:: kind = 'second' + +These are logically equivalent to ``Trunc('datetime_field', kind)``. They +truncate all parts of the date up to ``kind`` and allow grouping or filtering +datetimes with less precision. ``expression`` must have an ``output_field`` of +``DateTimeField``. + +Usage example:: + + >>> 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=), + 'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=), + 'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=), + 'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=) + } + ``TimeField`` truncation ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -745,77 +666,161 @@ that deal with time-parts can be used with ``TimeField``:: 2014-06-16 00:00:00+10:00 2 2016-01-01 04:00:00+11:00 1 -``DateTimeField`` truncation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _text-functions: -.. class:: TruncDate(expression, **extra) +Text Functions +============== - .. attribute:: lookup_name = 'date' - .. attribute:: output_field = DateField() +``Concat`` +---------- -``TruncDate`` casts ``expression`` to a date rather than using the built-in SQL -truncate function. It's also registered as a transform on ``DateTimeField`` as -``__date``. +.. class:: Concat(*expressions, **extra) -.. class:: TruncTime(expression, **extra) +Accepts a list of at least two text fields or expressions and returns the +concatenated text. Each argument must be of a text or char type. If you want +to concatenate a ``TextField()`` with a ``CharField()``, then be sure to tell +Django that the ``output_field`` should be a ``TextField()``. Specifying an +``output_field`` is also required when concatenating a ``Value`` as in the +example below. - .. attribute:: lookup_name = 'time' - .. attribute:: output_field = TimeField() +This function will never have a null result. On backends where a null argument +results in the entire expression being null, Django will ensure that each null +part is converted to an empty string first. -``TruncTime`` casts ``expression`` to a time rather than using the built-in SQL -truncate function. It's also registered as a transform on ``DateTimeField`` as -``__time``. +Usage example:: -.. class:: TruncDay(expression, output_field=None, tzinfo=None, **extra) + >>> # 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) - .. attribute:: kind = 'day' +``Length`` +---------- -.. class:: TruncHour(expression, output_field=None, tzinfo=None, **extra) +.. class:: Length(expression, **extra) - .. attribute:: kind = 'hour' +Accepts a single text field or expression and returns the number of characters +the value has. If the expression is null, then the length will also be null. -.. class:: TruncMinute(expression, output_field=None, tzinfo=None, **extra) +Usage example:: - .. attribute:: kind = 'minute' + >>> # 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) -.. class:: TruncSecond(expression, output_field=None, tzinfo=None, **extra) +It can also be registered as a transform. For example:: - .. attribute:: kind = 'second' + >>> 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) -These are logically equivalent to ``Trunc('datetime_field', kind)``. They -truncate all parts of the date up to ``kind`` and allow grouping or filtering -datetimes with less precision. ``expression`` must have an ``output_field`` of -``DateTimeField``. +``Lower`` +--------- + +.. class:: Lower(expression, **extra) + +Accepts a single text field or expression and returns the lowercase +representation. + +It can also be registered as a transform as described in :class:`Length`. Usage example:: - >>> 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=), - 'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=), - 'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=), - 'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=) - } + >>> 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) + +.. versionadded:: 2.0 + +Returns a positive integer corresponding to the 1-indexed position of the first +occurrence of ``substring`` inside ``string``, or 0 if ``substring`` is not +found. + +Usage example:: + + >>> 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) + , ]> + +.. warning:: + + In MySQL, a database table's :ref:`collation` determines + whether string comparisons (such as the ``expression`` and ``substring`` of + this function) are case-sensitive. Comparisons are case-insensitive by + default. + +``Substr`` +---------- + +.. class:: Substr(expression, pos, length=None, **extra) + +Returns a substring of length ``length`` from the field or expression starting +at position ``pos``. The position is 1-indexed, so the position must be greater +than 0. If ``length`` is ``None``, then the rest of the string will be returned. + +Usage example:: + + >>> # Set the alias to the first 5 characters of the name as lowercase + >>> from django.db.models.functions import Substr, Lower + >>> Author.objects.create(name='Margaret Smith') + >>> Author.objects.update(alias=Lower(Substr('name', 1, 5))) + 1 + >>> print(Author.objects.get(name='Margaret Smith').alias) + marga + +``Upper`` +--------- + +.. class:: Upper(expression, **extra) + +Accepts a single text field or expression and returns the uppercase +representation. + +It can also be registered as a transform as described in :class:`Length`. + +Usage example:: + + >>> 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-functions: -Window functions +Window Functions ================ .. versionadded:: 2.0 diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index cf59598977185..71455da279ae9 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -423,12 +423,12 @@ Models * A proxy model may now inherit multiple proxy models that share a common non-abstract parent class. -* Added :class:`~django.db.models.functions.datetime.Extract` functions - to extract datetime components as integers, such as year and hour. +* Added :class:`~django.db.models.functions.Extract` functions to extract + datetime components as integers, such as year and hour. -* Added :class:`~django.db.models.functions.datetime.Trunc` functions to - truncate a date or datetime to a significant component. They enable queries - like sales-per-day or sales-per-hour. +* Added :class:`~django.db.models.functions.Trunc` functions to truncate a date + or datetime to a significant component. They enable queries like + sales-per-day or sales-per-hour. * ``Model.__init__()`` now sets values of virtual fields from its keyword arguments. @@ -894,8 +894,8 @@ Miscellaneous yourself. * Private expressions ``django.db.models.expressions.Date`` and ``DateTime`` - are removed. The new :class:`~django.db.models.functions.datetime.Trunc` - expressions provide the same functionality. + are removed. The new :class:`~django.db.models.functions.Trunc` expressions + provide the same functionality. * The ``_base_manager`` and ``_default_manager`` attributes are removed from model instances. They remain accessible on the model class. diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index 2a539441d5254..ff4c1ebfef10e 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -330,16 +330,16 @@ Models (This validator moved to the form field in :doc:`Django 1.11.2 <1.11.2>`.) * Added support for time truncation to - :class:`~django.db.models.functions.datetime.Trunc` functions. + :class:`~django.db.models.functions.Trunc` functions. -* Added the :class:`~django.db.models.functions.datetime.ExtractWeek` function - to extract the week from :class:`~django.db.models.DateField` and +* Added the :class:`~django.db.models.functions.ExtractWeek` function to + extract the week from :class:`~django.db.models.DateField` and :class:`~django.db.models.DateTimeField` and exposed it through the :lookup:`week` lookup. -* Added the :class:`~django.db.models.functions.datetime.TruncTime` function - to truncate :class:`~django.db.models.DateTimeField` to its time component - and exposed it through the :lookup:`time` lookup. +* Added the :class:`~django.db.models.functions.TruncTime` function to truncate + :class:`~django.db.models.DateTimeField` to its time component and exposed it + through the :lookup:`time` lookup. * Added support for expressions in :meth:`.QuerySet.values` and :meth:`~.QuerySet.values_list`. diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt index 1ee994b613c4a..04ff9f540209c 100644 --- a/docs/releases/2.0.txt +++ b/docs/releases/2.0.txt @@ -245,20 +245,20 @@ Models :attr:`Meta.get_latest_by ` now allow ordering by several fields. -* Added the :class:`~django.db.models.functions.datetime.ExtractQuarter` - function to extract the quarter from :class:`~django.db.models.DateField` and +* Added the :class:`~django.db.models.functions.ExtractQuarter` function to + extract the quarter from :class:`~django.db.models.DateField` and :class:`~django.db.models.DateTimeField`, and exposed it through the :lookup:`quarter` lookup. -* Added the :class:`~django.db.models.functions.datetime.TruncQuarter` - function to truncate :class:`~django.db.models.DateField` and +* Added the :class:`~django.db.models.functions.TruncQuarter` function to + truncate :class:`~django.db.models.DateField` and :class:`~django.db.models.DateTimeField` to the first day of a quarter. * Added the :attr:`~django.db.models.Index.db_tablespace` parameter to class-based indexes. * If the database supports a native duration field (Oracle and PostgreSQL), - :class:`~django.db.models.functions.datetime.Extract` now works with + :class:`~django.db.models.functions.Extract` now works with :class:`~django.db.models.DurationField`. * Added the ``of`` argument to :meth:`.QuerySet.select_for_update()`, supported