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,
|
||||
)
|
||||
from .text import (
|
||||
Chr, Concat, ConcatPair, Left, Length, Lower, Ord, Replace, Right,
|
||||
StrIndex, Substr, Upper,
|
||||
Chr, Concat, ConcatPair, Left, Length, Lower, LTrim, Ord, Replace, Right,
|
||||
RTrim, StrIndex, Substr, Trim, Upper,
|
||||
)
|
||||
from .window import (
|
||||
CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
|
||||
|
@ -24,8 +24,8 @@ __all__ = [
|
|||
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
|
||||
'TruncWeek', 'TruncYear',
|
||||
# text
|
||||
'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'Ord', 'Replace',
|
||||
'Right', 'StrIndex', 'Substr', 'Upper',
|
||||
'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LTrim', 'Ord',
|
||||
'Replace', 'Right', 'RTrim', 'StrIndex', 'Substr', 'Trim', 'Upper',
|
||||
# window
|
||||
'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead',
|
||||
'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber',
|
||||
|
|
|
@ -110,6 +110,11 @@ class Lower(Transform):
|
|||
lookup_name = 'lower'
|
||||
|
||||
|
||||
class LTrim(Transform):
|
||||
function = 'LTRIM'
|
||||
lookup_name = 'ltrim'
|
||||
|
||||
|
||||
class Ord(Transform):
|
||||
function = 'ASCII'
|
||||
lookup_name = 'ord'
|
||||
|
@ -136,6 +141,11 @@ class Right(Left):
|
|||
return Substr(self.source_expressions[0], self.source_expressions[1] * Value(-1))
|
||||
|
||||
|
||||
class RTrim(Transform):
|
||||
function = 'RTRIM'
|
||||
lookup_name = 'rtrim'
|
||||
|
||||
|
||||
class StrIndex(Func):
|
||||
"""
|
||||
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')
|
||||
|
||||
|
||||
class Trim(Transform):
|
||||
function = 'TRIM'
|
||||
lookup_name = 'trim'
|
||||
|
||||
|
||||
class Upper(Transform):
|
||||
function = 'UPPER'
|
||||
lookup_name = 'upper'
|
||||
|
|
|
@ -800,6 +800,16 @@ Usage example::
|
|||
>>> print(author.name_lower)
|
||||
margaret smith
|
||||
|
||||
``LTrim``
|
||||
---------
|
||||
|
||||
.. class:: LTrim(expression, **extra)
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
Similar to :class:`~django.db.models.functions.Trim`, but removes only leading
|
||||
spaces.
|
||||
|
||||
``Ord``
|
||||
-------
|
||||
|
||||
|
@ -862,6 +872,16 @@ Usage example::
|
|||
>>> print(author.last_letter)
|
||||
h
|
||||
|
||||
``RTrim``
|
||||
---------
|
||||
|
||||
.. class:: RTrim(expression, **extra)
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
Similar to :class:`~django.db.models.functions.Trim`, but removes only trailing
|
||||
spaces.
|
||||
|
||||
``StrIndex``
|
||||
------------
|
||||
|
||||
|
@ -915,6 +935,25 @@ Usage example::
|
|||
>>> print(Author.objects.get(name='Margaret Smith').alias)
|
||||
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``
|
||||
---------
|
||||
|
||||
|
|
|
@ -204,10 +204,13 @@ Models
|
|||
|
||||
* A number of new text database functions are added:
|
||||
:class:`~django.db.models.functions.Chr`,
|
||||
:class:`~django.db.models.functions.Ord`,
|
||||
:class:`~django.db.models.functions.Left`,
|
||||
:class:`~django.db.models.functions.Right`, and
|
||||
:class:`~django.db.models.functions.Replace`.
|
||||
:class:`~django.db.models.functions.LTrim`,
|
||||
: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
|
||||
: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