Django Union of ManyToMany模型查询集

时间:2017-08-31 18:31:05

标签: python django django-models

这是一个基本的多对多关系模型:

from django.db import models                                                                     

class ManyToManyModel(models.Model):                                                             
    name = models.CharField(max_length=50)                                                       

class MainModel(models.Model):                                                                   
    name = models.CharField(max_length=50)                                                       
    many_to_many_ref = models.ManyToManyField(ManyToManyModel)

我按如下方式创建这些模型的实例,将ManyToManyModel个实例绑定到MainModel个实例:

from app1.models import ManyToManyModel, MainModel
m2m1 = ManyToManyModel(name='Number 1')
m2m1.save()
m2m2 = ManyToManyModel(name='Number 2') 
m2m2.save()
m2m3 = ManyToManyModel(name='Number 3') 
m2m3.save()
m2m4 = ManyToManyModel(name='Number 4') 
m2m4.save()

mm1 = MainModel(name='Main 1') 
mm1.save()
mm1.many_to_many_ref.add(m2m1)
mm1.save()

mm2 = MainModel(name='Main 2') 
mm2.save()
mm2.many_to_many_ref.add(m2m1)
mm2.many_to_many_ref.add(m2m2)
mm2.many_to_many_ref.add(m2m3)
mm2.save()

mm3 = MainModel(name='Main 3') 
mm3.save()
mm3.many_to_many_ref.add(m2m4)
mm3.save()

现在,我希望得到一个与所有ManyToManyModel个对象关联的所有MainModel的Queryset。可能有更好的方法来执行此操作,但此示例使用union(django 1.11中的新增内容):

for mm in MainModel.objects.all():
    try:
        m2m_union = m2m_union.union(mm.many_to_many_ref.all())
    except NameError:
        m2m_union = mm.many_to_many_ref.all()

现在,m2m_union在其QuerySet中包含四个条目,但让我们过滤掉我关心的一个条目,例如此查询只应返回ManyToManyModel name='Number 1'

m2m_union.get(name__endswith='1')

这会返回以下错误:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File ".../lib/python3.6/site-packages/django/db/models/query.py", line 384, in get
    (self.model._meta.object_name, num)
app1.models.MultipleObjectsReturned: get() returned more than one ManyToManyModel -- it returned 4!

但是,如果我直接查询ManyToManyModel个实例并尝试以这种方式获取对象,则可行:

ManyToManyModel.objects.all().get(name__endswith='1')

为什么迭代union创建的QuerySet行为不一样?

1 个答案:

答案 0 :(得分:1)

执行union后,您无法进行过滤。如上所述in the documentation

  

...只有LIMIT,OFFSET,COUNT(*)和ORDER BY(即切片,count(),   在得到的QuerySet上允许使用order_by())。进一步,   数据库限制了允许的操作   合并查询。例如,大多数数据库不允许LIMIT或   组合查询中的OFFSET。

在您的情况下,您实际上可以获得所需的对象:

m2m_union.order_by('name').first()

但当然,这不是你想要的,你会在结合前过滤所需的字段。