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.

Tomasz Jakub Rup
  • 10,502
  • 7
  • 48
  • 49
tjazz
  • 121
  • 1
  • 7

2 Answers2

2

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
  • 95,872
  • 14
  • 179
  • 191
  • 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 Jul 14 '09 at 11:11
2

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

C.objects.filter(classA__fieldOfA='foo') | C.objects.filter(classB__fieldOfB='foo')
ironfroggy
  • 7,991
  • 7
  • 33
  • 44