select_related() with filter() + Q()

2.2k views Asked by At
class A(models.Model):
    pass

class B(models.Model):
    a = models.ForeignKey(A)
    content_type = models.ForeignKey(ContentType)
    object_id = models.IntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

How to get A-instance, which linked with some B-instances by its parameters. I try do that:

instances = { '1':10, '2':20, '3':30 }
for ct, id in instances.items():
qset |= Q(content_type=int(ct), object_id=int(id))
a = A.objects.all().select_related().filter(qset)

It's no working with error: «Cannot resolve keyword 'object_id' into field.» What can I get A by linked B?

Thanx!

[PS] Now this working, but not quite as it should:

a_all = A.objects.all()
for a in a_all:
    print a.a_set.filter(qset)
2

There are 2 answers

1
Mikael On

Filter on B instead and then from B get the A instances

instances = { '1':10, '2':20, '3':30 }

for ct, id in instances.items():
    qset = qset | Q(content_type=int(ct), id=int(id))

b_with_a = B.objects.select_related().filter(qset)

for each b in b_with_a:
    print b.A.what_ever_field

Note that I build one qset with all queries instead of making the call to retreive b_with_a for every step in the loop. Change that if it doesn't fit your purpose.

0
okm On

You could use lookups which span relationships

import operator
instances = { '1':10, '2':20, '3':30 }
# note the 'b__'
qset = reduce(operator.or_, (Q(b__content_type=int(x), b__object_id=y)
                             for x,y in instances.iteritems()))
qs = A.objects.filter(qset)