@@ -83,57 +83,67 @@ def setUpTestData(cls):
83
83
)
84
84
85
85
cls .null_objs = NullableJSONModel .objects .bulk_create (NullableJSONModel () for _ in range (5 ))
86
- cls .null_objs .append (NullableJSONModel .objects .create (value = {"name" : None }))
87
86
cls .unique_id = ObjectId ()
87
+ for model in (Book , NullableJSONModel ):
88
+ collection = connection .database .get_collection (model ._meta .db_table )
89
+ collection .insert_one ({"_id" : cls .unique_id })
88
90
89
- def _test_none_filter_nullable_json (self , op , predicate , field ):
91
+ def test_none_filter_nullable_json_exact (self ):
90
92
with self .assertNumQueries (1 ) as ctx :
91
93
self .assertQuerySetEqual (
92
- NullableJSONModel .objects .filter (
93
- ** {f"{ field } __{ op } " : [None ] if op == "in" else None }
94
- ),
95
- [],
94
+ NullableJSONModel .objects .filter (value = None ),
95
+ self .null_objs [:- 1 ],
96
96
)
97
97
self .assertAggregateQuery (
98
98
ctx .captured_queries [0 ]["sql" ],
99
99
"lookup__nullablejsonmodel" ,
100
- [{"$match" : {"$and" : [{"$exists" : False }, predicate ( field ) ]}}],
100
+ [{"$match" : {"$and" : [{"value" : { " $exists" : True }}, { "value" : None } ]}}],
101
101
)
102
102
103
- def _test_none_filter_binary_operator (self , op , predicate , field ):
103
+ def test_none_filter_nullable_json_in (self ):
104
104
with self .assertNumQueries (1 ) as ctx :
105
105
self .assertQuerySetEqual (
106
- Book .objects .filter (** {f"{ field } __{ op } " : [None ] if op == "in" else None }), []
106
+ NullableJSONModel .objects .filter (value__in = [None ]),
107
+ self .null_objs [:- 1 ],
107
108
)
109
+ self .assertAggregateQuery (
110
+ ctx .captured_queries [0 ]["sql" ],
111
+ "lookup__nullablejsonmodel" ,
112
+ [{"$match" : {"$and" : [{"value" : {"$exists" : True }}, {"value" : {"$in" : [None ]}}]}}],
113
+ )
114
+
115
+ def test_none_filter_binary_operator_exact (self ):
116
+ with self .assertNumQueries (1 ) as ctx :
117
+ self .assertQuerySetEqual (Book .objects .filter (title = None ), [])
108
118
self .assertAggregateQuery (
109
119
ctx .captured_queries [0 ]["sql" ],
110
120
"lookup__book" ,
111
121
[
112
122
{
113
123
"$match" : {
114
124
"$or" : [
115
- {"$and" : [{field : {"$exists" : True }}, predicate ( field ) ]},
116
- {"$expr" : {"$eq" : [{"$type" : f"$ { field } " }, "missing" ]}},
125
+ {"$and" : [{"title" : {"$exists" : True }}, { "title" : None } ]},
126
+ {"$expr" : {"$eq" : [{"$type" : "$title " }, "missing" ]}},
117
127
]
118
128
}
119
129
}
120
130
],
121
131
)
122
132
123
- def _test_with_raw_data (self , model , test_function , field ):
124
- collection = connection . database . get_collection ( model . _meta . db_table )
125
- try :
126
- collection . insert_one ({ "_id" : self .unique_id })
127
-
128
- for op , predicate in self . _OPERATOR_PREDICATE_MAP . items ():
129
- with self . subTest ( op = op ):
130
- test_function ( op , predicate , field )
131
-
132
- finally :
133
- collection . delete_one ({ "_id " : self . unique_id })
134
-
135
- def test_none_filter_nullable_json ( self ):
136
- self . _test_with_raw_data ( NullableJSONModel , self . _test_none_filter_nullable_json , "value" )
137
-
138
- def test_none_filter_binary_operator ( self ):
139
- self . _test_with_raw_data ( Book , self . _test_none_filter_binary_operator , "title" )
133
+ def test_none_filter_binary_operator_in (self ):
134
+ with self . assertNumQueries ( 1 ) as ctx :
135
+ self . assertQuerySetEqual ( Book . objects . filter ( title__in = [ None ]), [])
136
+ self .assertAggregateQuery (
137
+ ctx . captured_queries [ 0 ][ "sql" ],
138
+ "lookup__book" ,
139
+ [
140
+ {
141
+ "$match" : {
142
+ "$or" : [
143
+ { "$and " : [{ "title" : { "$exists" : True }}, { "title" : None }]},
144
+ { "$expr" : { "$eq" : [{ "$type" : "$title" }, "missing" ]}},
145
+ ]
146
+ }
147
+ }
148
+ ],
149
+ )
0 commit comments