mirror of https://github.com/django/django.git
Refs #32946 -- Changed internal usage of dynamic Q() objects construction to use non-kwargs initialization.
This prefers non-kwargs construction of dynamically generated Q() objects to create a single Q() object instead of many and then combining them, where possible.
This commit is contained in:
parent
5b8ef8aa5b
commit
9662193aea
|
@ -451,11 +451,12 @@ class EmptyFieldListFilter(FieldListFilter):
|
||||||
if self.lookup_val not in ('0', '1'):
|
if self.lookup_val not in ('0', '1'):
|
||||||
raise IncorrectLookupParameters
|
raise IncorrectLookupParameters
|
||||||
|
|
||||||
lookup_condition = models.Q()
|
lookup_conditions = []
|
||||||
if self.field.empty_strings_allowed:
|
if self.field.empty_strings_allowed:
|
||||||
lookup_condition |= models.Q(**{self.field_path: ''})
|
lookup_conditions.append((self.field_path, ''))
|
||||||
if self.field.null:
|
if self.field.null:
|
||||||
lookup_condition |= models.Q(**{'%s__isnull' % self.field_path: True})
|
lookup_conditions.append((f'{self.field_path}__isnull', True))
|
||||||
|
lookup_condition = models.Q(*lookup_conditions, _connector=models.Q.OR)
|
||||||
if self.lookup_val == '1':
|
if self.lookup_val == '1':
|
||||||
return queryset.filter(lookup_condition)
|
return queryset.filter(lookup_condition)
|
||||||
return queryset.exclude(lookup_condition)
|
return queryset.exclude(lookup_condition)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import operator
|
|
||||||
import re
|
import re
|
||||||
from functools import partial, reduce, update_wrapper
|
from functools import partial, update_wrapper
|
||||||
from urllib.parse import quote as urlquote
|
from urllib.parse import quote as urlquote
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
@ -1035,9 +1034,11 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
for bit in smart_split(search_term):
|
for bit in smart_split(search_term):
|
||||||
if bit.startswith(('"', "'")) and bit[0] == bit[-1]:
|
if bit.startswith(('"', "'")) and bit[0] == bit[-1]:
|
||||||
bit = unescape_string_literal(bit)
|
bit = unescape_string_literal(bit)
|
||||||
or_queries = [models.Q(**{orm_lookup: bit})
|
or_queries = models.Q(
|
||||||
for orm_lookup in orm_lookups]
|
*((orm_lookup, bit) for orm_lookup in orm_lookups),
|
||||||
queryset = queryset.filter(reduce(operator.or_, or_queries))
|
_connector=models.Q.OR,
|
||||||
|
)
|
||||||
|
queryset = queryset.filter(or_queries)
|
||||||
may_have_duplicates |= any(
|
may_have_duplicates |= any(
|
||||||
lookup_spawns_duplicates(self.opts, search_spec)
|
lookup_spawns_duplicates(self.opts, search_spec)
|
||||||
for search_spec in orm_lookups
|
for search_spec in orm_lookups
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
import operator
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
@ -571,16 +570,16 @@ def create_generic_related_manager(superclass, rel):
|
||||||
queryset = queryset.using(queryset._db or self._db)
|
queryset = queryset.using(queryset._db or self._db)
|
||||||
# Group instances by content types.
|
# Group instances by content types.
|
||||||
content_type_queries = (
|
content_type_queries = (
|
||||||
models.Q(**{
|
models.Q(
|
||||||
'%s__pk' % self.content_type_field_name: content_type_id,
|
(f'{self.content_type_field_name}__pk', content_type_id),
|
||||||
'%s__in' % self.object_id_field_name: {obj.pk for obj in objs}
|
(f'{self.object_id_field_name}__in', {obj.pk for obj in objs}),
|
||||||
})
|
)
|
||||||
for content_type_id, objs in itertools.groupby(
|
for content_type_id, objs in itertools.groupby(
|
||||||
sorted(instances, key=lambda obj: self.get_content_type(obj).pk),
|
sorted(instances, key=lambda obj: self.get_content_type(obj).pk),
|
||||||
lambda obj: self.get_content_type(obj).pk,
|
lambda obj: self.get_content_type(obj).pk,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
query = functools.reduce(operator.or_, content_type_queries)
|
query = models.Q(*content_type_queries, _connector=models.Q.OR)
|
||||||
# We (possibly) need to convert object IDs to the type of the
|
# We (possibly) need to convert object IDs to the type of the
|
||||||
# instances' PK in order to match up instances:
|
# instances' PK in order to match up instances:
|
||||||
object_id_converter = instances[0]._meta.pk.to_python
|
object_id_converter = instances[0]._meta.pk.to_python
|
||||||
|
|
|
@ -971,8 +971,8 @@ class Model(metaclass=ModelBase):
|
||||||
op = 'gt' if is_next else 'lt'
|
op = 'gt' if is_next else 'lt'
|
||||||
order = '' if is_next else '-'
|
order = '' if is_next else '-'
|
||||||
param = getattr(self, field.attname)
|
param = getattr(self, field.attname)
|
||||||
q = Q(**{'%s__%s' % (field.name, op): param})
|
q = Q((field.name, param), (f'pk__{op}', self.pk), _connector=Q.AND)
|
||||||
q = q | Q(**{field.name: param, 'pk__%s' % op: self.pk})
|
q = Q(q, (f'{field.name}__{op}', param), _connector=Q.OR)
|
||||||
qs = self.__class__._default_manager.using(self._state.db).filter(**kwargs).filter(q).order_by(
|
qs = self.__class__._default_manager.using(self._state.db).filter(**kwargs).filter(q).order_by(
|
||||||
'%s%s' % (order, field.name), '%spk' % order
|
'%s%s' % (order, field.name), '%spk' % order
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import operator
|
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
from functools import partial, reduce
|
from functools import partial
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
|
@ -347,10 +346,13 @@ class Collector:
|
||||||
"""
|
"""
|
||||||
Get a QuerySet of the related model to objs via related fields.
|
Get a QuerySet of the related model to objs via related fields.
|
||||||
"""
|
"""
|
||||||
predicate = reduce(operator.or_, (
|
predicate = query_utils.Q(
|
||||||
query_utils.Q(**{'%s__in' % related_field.name: objs})
|
*(
|
||||||
for related_field in related_fields
|
(f'{related_field.name}__in', objs)
|
||||||
))
|
for related_field in related_fields
|
||||||
|
),
|
||||||
|
_connector=query_utils.Q.OR,
|
||||||
|
)
|
||||||
return related_model._base_manager.using(self.using).filter(predicate)
|
return related_model._base_manager.using(self.using).filter(predicate)
|
||||||
|
|
||||||
def instances_with_model(self):
|
def instances_with_model(self):
|
||||||
|
|
|
@ -359,12 +359,12 @@ class RelatedField(FieldCacheMixin, Field):
|
||||||
select all instances of self.related_field.model related through
|
select all instances of self.related_field.model related through
|
||||||
this field to obj. obj is an instance of self.model.
|
this field to obj. obj is an instance of self.model.
|
||||||
"""
|
"""
|
||||||
base_filter = {
|
base_filter = (
|
||||||
rh_field.attname: getattr(obj, lh_field.attname)
|
(rh_field.attname, getattr(obj, lh_field.attname))
|
||||||
for lh_field, rh_field in self.related_fields
|
for lh_field, rh_field in self.related_fields
|
||||||
}
|
)
|
||||||
descriptor_filter = self.get_extra_descriptor_filter(obj)
|
descriptor_filter = self.get_extra_descriptor_filter(obj)
|
||||||
base_q = Q(**base_filter)
|
base_q = Q(*base_filter)
|
||||||
if isinstance(descriptor_filter, dict):
|
if isinstance(descriptor_filter, dict):
|
||||||
return base_q & Q(**descriptor_filter)
|
return base_q & Q(**descriptor_filter)
|
||||||
elif descriptor_filter:
|
elif descriptor_filter:
|
||||||
|
|
|
@ -866,18 +866,17 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
||||||
do_not_call_in_templates = True
|
do_not_call_in_templates = True
|
||||||
|
|
||||||
def _build_remove_filters(self, removed_vals):
|
def _build_remove_filters(self, removed_vals):
|
||||||
filters = Q(**{self.source_field_name: self.related_val})
|
filters = Q((self.source_field_name, self.related_val))
|
||||||
# No need to add a subquery condition if removed_vals is a QuerySet without
|
# No need to add a subquery condition if removed_vals is a QuerySet without
|
||||||
# filters.
|
# filters.
|
||||||
removed_vals_filters = (not isinstance(removed_vals, QuerySet) or
|
removed_vals_filters = (not isinstance(removed_vals, QuerySet) or
|
||||||
removed_vals._has_filters())
|
removed_vals._has_filters())
|
||||||
if removed_vals_filters:
|
if removed_vals_filters:
|
||||||
filters &= Q(**{'%s__in' % self.target_field_name: removed_vals})
|
filters &= Q((f'{self.target_field_name}__in', removed_vals))
|
||||||
if self.symmetrical:
|
if self.symmetrical:
|
||||||
symmetrical_filters = Q(**{self.target_field_name: self.related_val})
|
symmetrical_filters = Q((self.target_field_name, self.related_val))
|
||||||
if removed_vals_filters:
|
if removed_vals_filters:
|
||||||
symmetrical_filters &= Q(
|
symmetrical_filters &= Q((f'{self.source_field_name}__in', removed_vals))
|
||||||
**{'%s__in' % self.source_field_name: removed_vals})
|
|
||||||
filters |= symmetrical_filters
|
filters |= symmetrical_filters
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue