add option to filter by free regex

and option to search by whole word
This commit is contained in:
Ido Shraga 2021-09-10 16:28:06 +03:00
parent 7e10bb2894
commit 6bc1b83695
3 changed files with 48 additions and 3 deletions

View File

@ -157,10 +157,17 @@ class StringField(BaseField):
regex = r"%s$" regex = r"%s$"
elif op == "exact": elif op == "exact":
regex = r"^%s$" regex = r"^%s$"
elif op == "has_word":
regex = r"\b%s\b"
elif op == "regex":
regex = value
# escape unsafe characters which could lead to a re.error # escape unsafe characters which could lead to a re.error
value = re.escape(value) if op == 'regex':
value = re.compile(regex % value, flags) value = re.compile(regex, flags)
else:
value = re.escape(value)
value = re.compile(regex % value, flags)
return super().prepare_query_value(op, value) return super().prepare_query_value(op, value)

View File

@ -51,6 +51,10 @@ STRING_OPERATORS = (
"iendswith", "iendswith",
"exact", "exact",
"iexact", "iexact",
"regex",
"iregex",
"has_word",
"ihas_word",
) )
CUSTOM_OPERATORS = ("match",) CUSTOM_OPERATORS = ("match",)
MATCH_OPERATORS = ( MATCH_OPERATORS = (

View File

@ -1257,6 +1257,35 @@ class TestQueryset(unittest.TestCase):
obj = self.Person.objects(name__iexact="gUIDO VAN rOSSU").first() obj = self.Person.objects(name__iexact="gUIDO VAN rOSSU").first()
assert obj is None assert obj is None
# Test has_word
obj = self.Person.objects(name__has_word="Guido").first()
assert obj == person
obj = self.Person.objects(name__has_word="rossum").first()
assert obj is None
obj = self.Person.objects(name__has_word="Rossu").first()
assert obj is None
# Test ihas_word
obj = self.Person.objects(name__ihas_word="rOSSUM").first()
assert obj == person
obj = self.Person.objects(name__ihas_word="rOSSU").first()
assert obj is None
# Test regex
obj = self.Person.objects(name__regex="^[Guido].*[Rossum]$").first()
assert obj == person
obj = self.Person.objects(name__regex="^[guido].*[rossum]$").first()
assert obj is None
obj = self.Person.objects(name__regex="^[uido].*[Rossum]$").first()
assert obj is None
# Test iregex
obj = self.Person.objects(name__iregex="^[guido].*[rossum]$").first()
assert obj == person
obj = self.Person.objects(name__iregex="^[Uido].*[Rossum]$").first()
assert obj is None
# Test unsafe expressions # Test unsafe expressions
person = self.Person(name="Guido van Rossum [.'Geek']") person = self.Person(name="Guido van Rossum [.'Geek']")
person.save() person.save()
@ -1341,7 +1370,12 @@ class TestQueryset(unittest.TestCase):
person.save() person.save()
people = self.Person.objects people = self.Person.objects
people = people.filter(name__startswith="Gui").filter(name__not__endswith="tum") people = people.filter(name__startswith="Gui")\
.filter(name__not__endswith="tum")\
.filter(name__icontains="VAN")\
.filter(name__regex="^Guido")\
.filter(name__has_word="Guido")\
.filter(name__has_word="van")
assert people.count() == 1 assert people.count() == 1
def assertSequence(self, qs, expected): def assertSequence(self, qs, expected):