diff --git a/django/contrib/mongodb/compiler.py b/django/contrib/mongodb/compiler.py index 9937e91345..f4791fd674 100644 --- a/django/contrib/mongodb/compiler.py +++ b/django/contrib/mongodb/compiler.py @@ -1,3 +1,5 @@ +import re + from pymongo import ASCENDING, DESCENDING from django.db.models.sql.datastructures import FullResultSet, EmptyResultSet @@ -11,6 +13,8 @@ class SQLCompiler(object): "isnull": lambda params, value_annotation, negated: {"$ne": None} if value_annotation == negated else None, "gt": lambda params, value_annotation, negated: {"$gt": params[0]}, "in": lambda params, value_annotation, negated: {"$in": params}, + "regex": lambda params, value_annotation, negated: re.compile(params[0]), + "iregex": lambda params, value_annotations, negated: re.compile(params[0], re.I) } def __init__(self, query, connection, using): @@ -54,7 +58,9 @@ class SQLCompiler(object): return column, self.LOOKUP_TYPES[lookup_type](params, value_annotation, negated) def negate(self, k, v): - if isinstance(v, dict): + # Regex lookups are of the form {"field": re.compile("pattern") and + # need to be negated with $not, not $ne. + if isinstance(v, dict) or isinstance(v, re._pattern_type): return {k: {"$not": v}} return {k: {"$ne": v}} diff --git a/tests/regressiontests/mongodb/tests.py b/tests/regressiontests/mongodb/tests.py index 13177ffa9f..ace0b4fdec 100644 --- a/tests/regressiontests/mongodb/tests.py +++ b/tests/regressiontests/mongodb/tests.py @@ -284,3 +284,31 @@ class MongoTestCase(TestCase): ], lambda g: g.name, ) + + def test_regex(self): + q = Group.objects.create(name="Queen") + e = Group.objects.create(name="The E Street Band") + b = Group.objects.create(name="The Beatles") + + self.assertQuerysetEqual( + Group.objects.filter(name__regex="^The"), [ + "The E Street Band", + "The Beatles", + ], + lambda g: g.name + ) + + self.assertQuerysetEqual( + Group.objects.filter(name__iregex="^the"), [ + "The E Street Band", + "The Beatles", + ], + lambda g: g.name + ) + + self.assertQuerysetEqual( + Group.objects.exclude(name__regex="^The"), [ + "Queen", + ], + lambda g: g.name, + )