假设我有以下3个模型,其中2个模型中的每个模型与第3个模型都有M2M关系。
class FirstModel(models.Model):
third_model = models.ManyToMany('ThirdModel')
class SecondModel(models.Model):
third_model = models.ManyToMany('ThirdModel')
class ThirdModel(models.Model):
pass
现在,假设我有一个特定的SecondModel
对象和一个FirstModel
QuerySet
。我需要对QuerySet
进行过滤,以便生成的QuerySet
仅包含与FirstModel
关系设置为M2M
的{{1}}个ThirdModel
对象SecondModel
1}}对象的M2M
关系设置为ThirdModel
。
def some_filtering_method(first_model_qs, second_model):
third_models_set = second_model.third_model_set.all()
first_model_ids = list()
for third_model in third_models_set:
first_model_ids.append(
[first_model.pk
for first_model in third_model.first_model_set.all()])
intersection_of_first_model_ids = get_intersection(first_model_ids)
return first_model_qs.filter(pk__in=intersection_of_first_model_ids)
在Django中有更多Pythonic方式吗?我尝试了以下但没有成功(在查看原始查询之后,显然它为什么不起作用)。
import operator
from django.db.models import Q
def some_filtering_method(first_model_qs, second_model):
return first_model_qs.filter(
reduce(
operator.and_,
(Q(third_model_set__contains=x)
for x in second_model.third_model_set.all())
)
)
答案 0 :(得分:0)
我不确定最恐怖的方式,但最可能是 Djangonic 的方式是使用custom Manager。
在Django 1.6和之前的版本中,您需要单独设置Manager和QuerySet:
class SharedM2MSetQuerySet(models.QuerySet):
def shared(self):
pass
# your code here
class SharedM2MSetManager(models.Manager):
def get_queryset(self):
return PersonQuerySet(self.model, using=self._db)
def shared(self,other):
return self.get_queryset().shared(other)
class FirstModel(models.Model):
third_model = models.ManyToMany('ThirdModel')
manager = SharedM2MSetQuerySet.as_manager()
如果您使用的是Django 1.7,可以使用QuerySet as a Manager快捷方式,如下所示:
class SharedM2MSetQuerySet(models.Manager):
def shared(self,other):
pass
# your code here
class FirstModel(models.Model):
third_model = models.ManyToMany('ThirdModel')
manager = SharedM2MSetQuerySet.as_manager()
class SecondModel(models.Model):
third_model = models.ManyToMany('ThirdModel')
class ThirdModel(models.Model):
pass
在这两种情况下,这都允许您执行以下操作:
my_obj = SecondModel.objects.first()
for i in FirstModel.objects.shared(my_obj):
do_the_thing(i)