Reputation: 2431
Here's a basic many to many relationship model:
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)
I create instances of these models as follows, tying the ManyToManyModel
instances to MainModel
instances:
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()
Now, I want to get a Queryset of ALL ManyToManyModel
s associated with all MainModel
objects constructed. There may be a better way to do this, but this example uses union
(new in 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()
Now, the m2m_union
contains four entries in its QuerySet, but let's filter out to one that I care about, e.g. this query should only return ManyToManyModel
with name='Number 1'
:
m2m_union.get(name__endswith='1')
This returns the following error:
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!
However, if I query the ManyToManyModel
instances directly and try to get the object that way, it works:
ManyToManyModel.objects.all().get(name__endswith='1')
Why does the QuerySet created by the iterative union
not behave the same?
Upvotes: 0
Views: 956
Reputation: 8071
You can't filter after doing the union
. As stated in the documentation:
... only LIMIT, OFFSET, COUNT(*), and ORDER BY (i.e. slicing, count(), and order_by()) are allowed on the resulting QuerySet. Further, databases place restrictions on what operations are allowed in the combined queries. For example, most databases don’t allow LIMIT or OFFSET in the combined queries.
In your case you could actually get the object you want with:
m2m_union.order_by('name').first()
But of course that's not what you want, you would filter on the desired field before making the union.
Upvotes: 1