Python Django:筛选以检查列表中是否有两个/多个字段
我在Django这里有一个模型名,带有字段a和字段b。 我有一个python中的列表,其元组形式为(a,b) 我想要得到Django模型的所有实例,其中两个字段都在Python列表中 如果只有一个字段,这将很简单:Python Django:筛选以检查列表中是否有两个/多个字段,python,django,django-queryset,Python,Django,Django Queryset,我在Django这里有一个模型名,带有字段a和字段b。 我有一个python中的列表,其元组形式为(a,b) 我想要得到Django模型的所有实例,其中两个字段都在Python列表中 如果只有一个字段,这将很简单: my_filter_list = [a1, a2, a3] ModelNameHere.objects.filter(field_a__in=my_filter_list) 但对于多个字段,这不起作用 my_filter_list = [(a1, b1), (a2, b2), (a
my_filter_list = [a1, a2, a3]
ModelNameHere.objects.filter(field_a__in=my_filter_list)
但对于多个字段,这不起作用
my_filter_list = [(a1, b1), (a2, b2), (a3, b3)]
ModelNameHere.objects.filter( ? )
有没有办法同时检查两个字段
或者,是否有方法将我的\u filter\u列表转换为临时表,以便我可以在此处使用字段a和字段b作为联接键,将该表与modelname联接
编辑:
快速添加:我在字段A上设置了索引,但在字段b上没有设置索引。如果您的
my\u filter\u list
变量预计不会太长(因为您可能会遇到性能问题),您可以这样构造查询:
from django.db.models import Q
multi_field_filter = None
for field_a_val, field_b_val in my_filter_list:
# logical AND the two field values together
q = Q(field_a=field_a_val, field_b=field_b_val)
# logical OR the AND'd terms together
multi_field_filter = q if multi_field_filter is None else (multi_field_filter | q)
results = ModelNameHere.objects.all()
if multi_field_filter is not None:
results = ModelNameHere.objects.filter(multi_field_filter)
对于更长的列表,人们不希望生成大量的SQL来执行这些类型的查询。一个(可能是黑客的)解决方案还包括向模型中添加一个额外字段,该字段以可搜索的方式连接两个值,如下所示:
class ModelNameHere(models.Model):
field_a = models.IntegerField()
field_b = models.IntegerField()
fields_concat = models.CharField(max_length=200, blank=True, db_index=True)
def save(self, *args, **kwargs):
# automatically update on save
self.fields_concat = "%s.%s" % (self.field_a, self.field_b)
# call parent save
super(ModelNameHere, self).save(*args, **kwargs)
然后,当您要查找特定组合时,只需执行精确的文本搜索匹配:
# using set() automatically deduplicates any search combinations
concat_filters = set([
("%s.%s" % (field_a_val, field_b_val)) for field_a_val, field_b_val in my_filter_list
])
# do your lookup here
results = ModelNameHere.objects.filter(fields_concat__in=concat_filters)
如果您的
my\u filter\u list
变量预计不会太长(因为您可能会遇到性能问题),您可以构建如下查询:
from django.db.models import Q
multi_field_filter = None
for field_a_val, field_b_val in my_filter_list:
# logical AND the two field values together
q = Q(field_a=field_a_val, field_b=field_b_val)
# logical OR the AND'd terms together
multi_field_filter = q if multi_field_filter is None else (multi_field_filter | q)
results = ModelNameHere.objects.all()
if multi_field_filter is not None:
results = ModelNameHere.objects.filter(multi_field_filter)
对于更长的列表,人们不希望生成大量的SQL来执行这些类型的查询。一个(可能是黑客的)解决方案还包括向模型中添加一个额外字段,该字段以可搜索的方式连接两个值,如下所示:
class ModelNameHere(models.Model):
field_a = models.IntegerField()
field_b = models.IntegerField()
fields_concat = models.CharField(max_length=200, blank=True, db_index=True)
def save(self, *args, **kwargs):
# automatically update on save
self.fields_concat = "%s.%s" % (self.field_a, self.field_b)
# call parent save
super(ModelNameHere, self).save(*args, **kwargs)
然后,当您要查找特定组合时,只需执行精确的文本搜索匹配:
# using set() automatically deduplicates any search combinations
concat_filters = set([
("%s.%s" % (field_a_val, field_b_val)) for field_a_val, field_b_val in my_filter_list
])
# do your lookup here
results = ModelNameHere.objects.filter(fields_concat__in=concat_filters)
您可以使用枚举,如下与Q的组合:
from django.db.models import Q
result_list = []
my_filter_list = [(a1, b1), (a2, b2), (a3, b3)]
for n,m in enumerate(my_filter_list):
query_set = ModelNameHere.objects.filter(Q(field_a=n[0]) | Q(field_b=m[0]))
if query_set.count() >0:
result_list.append(query_set)
您可以使用枚举,如下与Q的组合:
from django.db.models import Q
result_list = []
my_filter_list = [(a1, b1), (a2, b2), (a3, b3)]
for n,m in enumerate(my_filter_list):
query_set = ModelNameHere.objects.filter(Q(field_a=n[0]) | Q(field_b=m[0]))
if query_set.count() >0:
result_list.append(query_set)
您可以对查询kwargs使用字典理解,并对查询集使用管道操作符或操作
query_fields = ({ 'field_a': value_a, 'field_b': value_b } for value_a, value_b in my_filter_list)
queryset = ModelNameHere.objects.none()
for query_kwarg in query_fields:
queryset |= ModelNameHere.objects.filter(**query_kwarg)
queryset = queryset.distinct()
您可以对查询kwargs使用字典理解,并对查询集使用管道操作符或操作
query_fields = ({ 'field_a': value_a, 'field_b': value_b } for value_a, value_b in my_filter_list)
queryset = ModelNameHere.objects.none()
for query_kwarg in query_fields:
queryset |= ModelNameHere.objects.filter(**query_kwarg)
queryset = queryset.distinct()
:
好的是,它是一个简单的查询,很容易理解
糟糕的是,您不仅会得到(a1,b1)和(a2,b2),还会得到(a1b1,)和(,a1b1)。如果它对您至关重要,请使用更复杂的分隔符(“:”)。:
好的是,它是一个简单的查询,很容易理解
糟糕的是,您不仅会得到(a1,b1)和(a2,b2),还会得到(a1b1,)和(,a1b1)。如果它对您很重要,请使用更复杂的分隔符(“:”)您是否想过将所有这些逻辑放入自定义QuerySet类?您是否想过将所有这些逻辑放入自定义QuerySet类?这将导致len(my_filter_list)许多查询,不是吗?不,只有一次。在所有情况下,查询总数都是相同的。它将只查询列表中的每个项目一次。这是必要和充分的。@FlorianDietz这是一个优化的解决方案。请重新考虑迭代。但是它不会发送len(my_filter_list)许多单独的查询,而另一个解决方案只发送一个查询吗?运行时在O(n)中应该是相同的,但是将如此多的查询转换为SQL并要求数据库执行它们可能会有很大的开销。@FlorianDietz Yes。但这就是要求,您需要检查这两个字段的每个值,如果第一个条件为真,或者不检查第二个条件,则它不会总是计算整个查询。这将导致len(my_filter_list)许多查询,不是吗?不,只有一次。在所有情况下,查询总数都是相同的。它将只查询列表中的每个项目一次。这是必要和充分的。@FlorianDietz这是一个优化的解决方案。请重新考虑迭代。但是它不会发送len(my_filter_list)许多单独的查询,而另一个解决方案只发送一个查询吗?运行时在O(n)中应该是相同的,但是将如此多的查询转换为SQL并要求数据库执行它们可能会有很大的开销。@FlorianDietz Yes。但这就是要求,您需要检查这两个字段的每一个值,如果第一个条件为真,或者没有检查第二个条件,那么它不会总是计算整个查询。这看起来很有趣。您知道生成的SQL是什么样子吗?它是否会像两个表之间的连接那样进行优化,还是会创建len(my_filter_list)许多查询并将它们合并?Django QuerySet是惰性的,在对其求值之前不会执行它
filter()
方法只需将所有查询累积到一个查询中。当计算queryset
时,将执行一个查询(即,当您在queryset
上循环时)。对不起,我的措辞很糟糕:我知道只有一个查询,但该查询的形式是否为“(选择…)UNION(选择…)UNION…”?实际上,我认为我对数据库的功能了解不够,无法知道这是比任何替代解决方案更快还是更慢:-(不,不会有任何联合查询,但更像是一系列左侧外部联接查询,这取决于您提供的查询字段的条件。这看起来很有趣。您知道生成的SQL是什么样子的吗?它是否像两个表之间的联接那样进行优化,还是会创建len(我的筛选器列表)许多查询并将它们合并?Django queryset是惰性的,在对其求值之前不会执行。filter()
方法仅将所有查询累积到一个查询中。当对queryset
求值时(即,在queryset
上循环时),将执行一个查询