views:

301

answers:

2

Consider the models:

#Models
class A(models.Model):
    fieldOfA = models.CharField(max_length = 4)
class B(models.Model):
    fieldOfB = models.CharField(max_length = 4)
class C(models.Model):
    classA = models.ForeignKey(A, blank=True, null=True)
    classB = models.ForeignKey(B, blank=True, null=True)

When I create objects of C, I ensure that an object has EITHER a classA or classB relationship.

I am looking for a single queryset, which gets me objects of C for specific fieldOfA or specific fieldOfB values.

I tried this, but it fails (returns [], despite there being valid results).

#Views - assume double underscore in the query
from django.db.models import Q
my_query = C.objects.filter(Q(classA _ _isnull = False, classA _ _fieldOfA = 'foo') | Q(classB _ _isnull = False, classB _ _fieldOfB = 'foo'))

The problem I see is the '|' that is the applied. Two different querysets for classA and classB work fine. Any way I could apply a single queryset to make this work? Or worse, a way to merge the individual querysets.

+2  A: 

If you can be sure that a C either has an A or a B but never both, your isnull constraints are redundant. What happens if you run the following?

C.objects.filter(Q(classA__fieldOfA = 'foo') | Q(classB__fieldOfB = 'foo'))

If that still doesn't work, run manage.py shell and after running the above query (ensuring that settings.DEBUG is True, check the generated SQL for the above with

>>> from django.db import connection
>>> connection.queries()

What do you see?

Vinay Sajip
Unfortunately, eliminating the redundancy didn't help.The SQL has two 'LEFT OUTER JOINS' for both the Q's (internally followed by an INNER JOIN). Shouldn't the second Q have a RIGHT OUTER JOIN? The fieldB values aren't restored.Thanks for the help though. I am chaining (merging, in a way) the two querysets now, which also works for me. Using this code snippet - http://www.djangosnippets.org/snippets/1103/
tjazz
+2  A: 

Actually, you can combine QuerySets in the same way. Like so:

C.objects.filter(classA__fieldOfA='foo') | C.objects.filter(classB__fieldOfB='foo')
ironfroggy