有关Q对象和外键的谜题
我有一个这样的模型:
class Thing(models.Model):
property1 = models.IntegerField()
property2 = models.IntegerField()
property3 = models.IntegerField()
class Subthing(models.Model):
subproperty = models.IntegerField()
thing = modelsForeignkey(Thing)
main = models.BooleanField()
我有一个函数,这个函数接收一个过滤器列表,每个过滤器的格式是 {'type':某种类型, 'value':值x}。这个函数需要返回一个结果集,要求把所有过滤器的条件都满足:
final_q = Q()
for filter in filters:
q = None
if filter['type'] =='thing-property1':
q = Q(property1=filter['value'])
elif filter['type'] =='thing-property2':
q = Q(property2=filter['value'])
elif filter['type'] =='thing-property2':
q = Q(property3=filter['value'])
if q:
final_q = final_q & q
return Thing.objects.filter(final_q).distinct()
每个子项(Subthing)都有一个布尔属性 'main'。每个主项(Thing)都有且仅有一个子项,其 'main' 属性为 True。
现在我需要添加一个过滤器,返回所有主项,这些主项的子项中有一个满足 main==True
且 subproperty==filter['value']
的条件。
我能在构建的 Q
对象中做到这一点吗?如果不能,还有其他方法吗?在我添加新过滤器之前,得到的查询集可能会很大,所以我希望有一种方法不需要逐个遍历结果。
2 个回答
1
使用这个(而不是一开始的 final_q=Q()
)
final_q=Q(subthing_set__main=True)
sub_vals = map(lambda v: v['value'], filters)
if sub_vals:
final_q = final_q & Q(subthing_set__subproperty__in=sub_vals)
应该能帮你达到想要的效果,你也可以调整你的循环,先构建 sub_vals 列表,然后在循环结束后再应用它。
subthing_set 是一个自动添加的相关字段,用于访问与 Thing 相关的 Subthings。
你可以给它指定另一个相关名称,比如:
thing=models.ForeignKey(Thing,related_name='subthings')
2
如果你在Subthings和Thing之间的关系中明确给Subthings一个“related_name”,那么理解起来会简单一些。
class Subthing(models.Model):
...
thing = models.ForeignKey(Thing, related_name='subthings')
...
现在,你可以使用Django的连接语法来构建你的Q对象:
Q(subthings__main=True) & Q(subthings__subproperty=filter['value'])
反向关系的默认名称是'subthing_set',但我觉得如果给它起个更好的名字,比如'subthings',会更容易理解。