Refs #28643 -- Added LTrim, RTrim, and Trim database functions.

Thanks Tim Graham and Mads Jensen for reviews.
This commit is contained in:
Mariusz Felisiak 2018-03-15 20:57:23 +01:00 committed by GitHub
parent 47bb3b68ff
commit 9421aee35e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 104 additions and 7 deletions

View File

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

View File

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

View File

@ -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``
--------- ---------

View File

@ -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

View File

@ -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)