mirror of https://github.com/django/django.git
Refs #28643 -- Added LTrim, RTrim, and Trim database functions.
Thanks Tim Graham and Mads Jensen for reviews.
This commit is contained in:
parent
47bb3b68ff
commit
9421aee35e
|
@ -6,8 +6,8 @@ from .datetime import (
|
||||||
TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
|
TruncQuarter, TruncSecond, TruncTime, TruncWeek, TruncYear,
|
||||||
)
|
)
|
||||||
from .text import (
|
from .text import (
|
||||||
Chr, Concat, ConcatPair, Left, Length, Lower, Ord, Replace, Right,
|
Chr, Concat, ConcatPair, Left, Length, Lower, LTrim, Ord, Replace, Right,
|
||||||
StrIndex, Substr, Upper,
|
RTrim, StrIndex, Substr, Trim, Upper,
|
||||||
)
|
)
|
||||||
from .window import (
|
from .window import (
|
||||||
CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
|
CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
|
||||||
|
@ -24,8 +24,8 @@ __all__ = [
|
||||||
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
|
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
|
||||||
'TruncWeek', 'TruncYear',
|
'TruncWeek', 'TruncYear',
|
||||||
# text
|
# text
|
||||||
'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'Ord', 'Replace',
|
'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LTrim', 'Ord',
|
||||||
'Right', 'StrIndex', 'Substr', 'Upper',
|
'Replace', 'Right', 'RTrim', 'StrIndex', 'Substr', 'Trim', 'Upper',
|
||||||
# window
|
# window
|
||||||
'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead',
|
'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead',
|
||||||
'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber',
|
'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber',
|
||||||
|
|
|
@ -110,6 +110,11 @@ class Lower(Transform):
|
||||||
lookup_name = 'lower'
|
lookup_name = 'lower'
|
||||||
|
|
||||||
|
|
||||||
|
class LTrim(Transform):
|
||||||
|
function = 'LTRIM'
|
||||||
|
lookup_name = 'ltrim'
|
||||||
|
|
||||||
|
|
||||||
class Ord(Transform):
|
class Ord(Transform):
|
||||||
function = 'ASCII'
|
function = 'ASCII'
|
||||||
lookup_name = 'ord'
|
lookup_name = 'ord'
|
||||||
|
@ -136,6 +141,11 @@ class Right(Left):
|
||||||
return Substr(self.source_expressions[0], self.source_expressions[1] * Value(-1))
|
return Substr(self.source_expressions[0], self.source_expressions[1] * Value(-1))
|
||||||
|
|
||||||
|
|
||||||
|
class RTrim(Transform):
|
||||||
|
function = 'RTRIM'
|
||||||
|
lookup_name = 'rtrim'
|
||||||
|
|
||||||
|
|
||||||
class StrIndex(Func):
|
class StrIndex(Func):
|
||||||
"""
|
"""
|
||||||
Return a positive integer corresponding to the 1-indexed position of the
|
Return a positive integer corresponding to the 1-indexed position of the
|
||||||
|
@ -174,6 +184,11 @@ class Substr(Func):
|
||||||
return super().as_sql(compiler, connection, function='SUBSTR')
|
return super().as_sql(compiler, connection, function='SUBSTR')
|
||||||
|
|
||||||
|
|
||||||
|
class Trim(Transform):
|
||||||
|
function = 'TRIM'
|
||||||
|
lookup_name = 'trim'
|
||||||
|
|
||||||
|
|
||||||
class Upper(Transform):
|
class Upper(Transform):
|
||||||
function = 'UPPER'
|
function = 'UPPER'
|
||||||
lookup_name = 'upper'
|
lookup_name = 'upper'
|
||||||
|
|
|
@ -800,6 +800,16 @@ Usage example::
|
||||||
>>> print(author.name_lower)
|
>>> print(author.name_lower)
|
||||||
margaret smith
|
margaret smith
|
||||||
|
|
||||||
|
``LTrim``
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. class:: LTrim(expression, **extra)
|
||||||
|
|
||||||
|
.. versionadded:: 2.1
|
||||||
|
|
||||||
|
Similar to :class:`~django.db.models.functions.Trim`, but removes only leading
|
||||||
|
spaces.
|
||||||
|
|
||||||
``Ord``
|
``Ord``
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -862,6 +872,16 @@ Usage example::
|
||||||
>>> print(author.last_letter)
|
>>> print(author.last_letter)
|
||||||
h
|
h
|
||||||
|
|
||||||
|
``RTrim``
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. class:: RTrim(expression, **extra)
|
||||||
|
|
||||||
|
.. versionadded:: 2.1
|
||||||
|
|
||||||
|
Similar to :class:`~django.db.models.functions.Trim`, but removes only trailing
|
||||||
|
spaces.
|
||||||
|
|
||||||
``StrIndex``
|
``StrIndex``
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -915,6 +935,25 @@ Usage example::
|
||||||
>>> print(Author.objects.get(name='Margaret Smith').alias)
|
>>> print(Author.objects.get(name='Margaret Smith').alias)
|
||||||
marga
|
marga
|
||||||
|
|
||||||
|
``Trim``
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. class:: Trim(expression, **extra)
|
||||||
|
|
||||||
|
.. versionadded:: 2.1
|
||||||
|
|
||||||
|
Returns the value of the given text field or expression with leading and
|
||||||
|
trailing spaces removed.
|
||||||
|
|
||||||
|
Usage example::
|
||||||
|
|
||||||
|
>>> 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``
|
``Upper``
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|
|
@ -204,10 +204,13 @@ Models
|
||||||
|
|
||||||
* A number of new text database functions are added:
|
* A number of new text database functions are added:
|
||||||
:class:`~django.db.models.functions.Chr`,
|
:class:`~django.db.models.functions.Chr`,
|
||||||
:class:`~django.db.models.functions.Ord`,
|
|
||||||
:class:`~django.db.models.functions.Left`,
|
:class:`~django.db.models.functions.Left`,
|
||||||
:class:`~django.db.models.functions.Right`, and
|
:class:`~django.db.models.functions.LTrim`,
|
||||||
:class:`~django.db.models.functions.Replace`.
|
:class:`~django.db.models.functions.Ord`,
|
||||||
|
:class:`~django.db.models.functions.Replace`,
|
||||||
|
:class:`~django.db.models.functions.Right`,
|
||||||
|
:class:`~django.db.models.functions.RTrim`, and
|
||||||
|
:class:`~django.db.models.functions.Trim`.
|
||||||
|
|
||||||
* The new :class:`~django.db.models.functions.TruncWeek` function truncates
|
* The new :class:`~django.db.models.functions.TruncWeek` function truncates
|
||||||
:class:`~django.db.models.DateField` and
|
:class:`~django.db.models.DateField` and
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
from django.db.models import CharField
|
||||||
|
from django.db.models.functions import LTrim, RTrim, Trim
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from .models import Author
|
||||||
|
|
||||||
|
|
||||||
|
class TrimTests(TestCase):
|
||||||
|
def test_trim(self):
|
||||||
|
Author.objects.create(name=' John ', alias='j')
|
||||||
|
Author.objects.create(name='Rhonda', alias='r')
|
||||||
|
authors = Author.objects.annotate(
|
||||||
|
ltrim=LTrim('name'),
|
||||||
|
rtrim=RTrim('name'),
|
||||||
|
trim=Trim('name'),
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(
|
||||||
|
authors.order_by('alias'), [
|
||||||
|
('John ', ' John', 'John'),
|
||||||
|
('Rhonda', 'Rhonda', 'Rhonda'),
|
||||||
|
],
|
||||||
|
lambda a: (a.ltrim, a.rtrim, a.trim)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_trim_transform(self):
|
||||||
|
Author.objects.create(name=' John ')
|
||||||
|
Author.objects.create(name='Rhonda')
|
||||||
|
tests = (
|
||||||
|
(LTrim, 'John '),
|
||||||
|
(RTrim, ' John'),
|
||||||
|
(Trim, 'John'),
|
||||||
|
)
|
||||||
|
for transform, trimmed_name in tests:
|
||||||
|
with self.subTest(transform=transform):
|
||||||
|
try:
|
||||||
|
CharField.register_lookup(transform)
|
||||||
|
authors = Author.objects.filter(**{'name__%s' % transform.lookup_name: trimmed_name})
|
||||||
|
self.assertQuerysetEqual(authors, [' John '], lambda a: a.name)
|
||||||
|
finally:
|
||||||
|
CharField._unregister_lookup(transform)
|
Loading…
Reference in New Issue