Refs #28643 -- Added Replace database function.
This commit is contained in:
parent
fcd431c6c3
commit
65728550bd
|
@ -5,7 +5,9 @@ from .datetime import (
|
||||||
Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth,
|
Now, Trunc, TruncDate, TruncDay, TruncHour, TruncMinute, TruncMonth,
|
||||||
TruncQuarter, TruncSecond, TruncTime, TruncYear,
|
TruncQuarter, TruncSecond, TruncTime, TruncYear,
|
||||||
)
|
)
|
||||||
from .text import Concat, ConcatPair, Length, Lower, StrIndex, Substr, Upper
|
from .text import (
|
||||||
|
Concat, ConcatPair, Length, Lower, Replace, StrIndex, Substr, Upper,
|
||||||
|
)
|
||||||
from .window import (
|
from .window import (
|
||||||
CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
|
CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
|
||||||
PercentRank, Rank, RowNumber,
|
PercentRank, Rank, RowNumber,
|
||||||
|
@ -21,7 +23,8 @@ __all__ = [
|
||||||
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
|
'TruncMinute', 'TruncMonth', 'TruncQuarter', 'TruncSecond', 'TruncTime',
|
||||||
'TruncYear',
|
'TruncYear',
|
||||||
# text
|
# text
|
||||||
'Concat', 'ConcatPair', 'Length', 'Lower', 'StrIndex', 'Substr', 'Upper',
|
'Concat', 'ConcatPair', 'Length', 'Lower', 'Replace', 'StrIndex', 'Substr',
|
||||||
|
'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',
|
||||||
|
|
|
@ -70,6 +70,13 @@ class Lower(Transform):
|
||||||
lookup_name = 'lower'
|
lookup_name = 'lower'
|
||||||
|
|
||||||
|
|
||||||
|
class Replace(Func):
|
||||||
|
function = 'REPLACE'
|
||||||
|
|
||||||
|
def __init__(self, expression, text, replacement=Value(''), **extra):
|
||||||
|
super().__init__(expression, text, replacement, **extra)
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -751,6 +751,28 @@ Usage example::
|
||||||
>>> print(author.name_lower)
|
>>> print(author.name_lower)
|
||||||
margaret smith
|
margaret smith
|
||||||
|
|
||||||
|
``Replace``
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. class:: Replace(expression, text, replacement=Value(''), **extra)
|
||||||
|
|
||||||
|
.. versionadded:: 2.1
|
||||||
|
|
||||||
|
Replaces all occurrences of ``text`` with ``replacement`` in ``expression``.
|
||||||
|
The default replacement text is the empty string. The arguments to the function
|
||||||
|
are case-sensitive.
|
||||||
|
|
||||||
|
Usage example::
|
||||||
|
|
||||||
|
>>> from django.db.models import Value
|
||||||
|
>>> from django.db.models.functions import Replace
|
||||||
|
>>> Author.objects.create(name='Margaret Johnson')
|
||||||
|
>>> Author.objects.create(name='Margaret Smith')
|
||||||
|
>>> Author.objects.update(name=Replace('name', Value('Margaret'), Value('Margareth')))
|
||||||
|
2
|
||||||
|
>>> Author.objects.values('name')
|
||||||
|
<QuerySet [{'name': 'Margareth Johnson'}, {'name': 'Margareth Smith'}]>
|
||||||
|
|
||||||
``StrIndex``
|
``StrIndex``
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,9 @@ Models
|
||||||
* A ``BinaryField`` may now be set to ``editable=True`` if you wish to include
|
* A ``BinaryField`` may now be set to ``editable=True`` if you wish to include
|
||||||
it in model forms.
|
it in model forms.
|
||||||
|
|
||||||
|
* The new :class:`~django.db.models.functions.Replace` database function
|
||||||
|
replaces strings in an expression.
|
||||||
|
|
||||||
Requests and Responses
|
Requests and Responses
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
from django.db.models import F, Value
|
||||||
|
from django.db.models.functions import Concat, Replace
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from .models import Author
|
||||||
|
|
||||||
|
|
||||||
|
class ReplaceTests(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
Author.objects.create(name='George R. R. Martin')
|
||||||
|
Author.objects.create(name='J. R. R. Tolkien')
|
||||||
|
|
||||||
|
def test_replace_with_empty_string(self):
|
||||||
|
qs = Author.objects.annotate(
|
||||||
|
without_middlename=Replace(F('name'), Value('R. R. '), Value('')),
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(qs, [
|
||||||
|
('George R. R. Martin', 'George Martin'),
|
||||||
|
('J. R. R. Tolkien', 'J. Tolkien'),
|
||||||
|
], transform=lambda x: (x.name, x.without_middlename), ordered=False)
|
||||||
|
|
||||||
|
def test_case_sensitive(self):
|
||||||
|
qs = Author.objects.annotate(same_name=Replace(F('name'), Value('r. r.'), Value('')))
|
||||||
|
self.assertQuerysetEqual(qs, [
|
||||||
|
('George R. R. Martin', 'George R. R. Martin'),
|
||||||
|
('J. R. R. Tolkien', 'J. R. R. Tolkien'),
|
||||||
|
], transform=lambda x: (x.name, x.same_name), ordered=False)
|
||||||
|
|
||||||
|
def test_replace_expression(self):
|
||||||
|
qs = Author.objects.annotate(same_name=Replace(
|
||||||
|
Concat(Value('Author: '), F('name')), Value('Author: '), Value('')),
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(qs, [
|
||||||
|
('George R. R. Martin', 'George R. R. Martin'),
|
||||||
|
('J. R. R. Tolkien', 'J. R. R. Tolkien'),
|
||||||
|
], transform=lambda x: (x.name, x.same_name), ordered=False)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
Author.objects.update(
|
||||||
|
name=Replace(F('name'), Value('R. R. '), Value('')),
|
||||||
|
)
|
||||||
|
self.assertQuerysetEqual(Author.objects.all(), [
|
||||||
|
('George Martin'),
|
||||||
|
('J. Tolkien'),
|
||||||
|
], transform=lambda x: x.name, ordered=False)
|
||||||
|
|
||||||
|
def test_replace_with_default_arg(self):
|
||||||
|
# The default replacement is an empty string.
|
||||||
|
qs = Author.objects.annotate(same_name=Replace(F('name'), Value('R. R. ')))
|
||||||
|
self.assertQuerysetEqual(qs, [
|
||||||
|
('George R. R. Martin', 'George Martin'),
|
||||||
|
('J. R. R. Tolkien', 'J. Tolkien'),
|
||||||
|
], transform=lambda x: (x.name, x.same_name), ordered=False)
|
Loading…
Reference in New Issue