Filter via related_name in inherited model not working .. Bug?

952 views
Skip to first unread message

robim42

unread,
Apr 15, 2011, 8:51:09 AM4/15/11
to Django developers
Hi guys,

I used model inheritance quite a while and came across a problem which
I can not resolve and actually think is might be a bug in django
itself.
Because of the size of the project I'm working on it would be a waste
of space using the original models here ... so I simplified the
classes to reproduce the problem.

--- models.py code --- snip ---
from django.db import models

class Base(models.Model):
name = models.CharField(max_length=20)

def __unicode__(self):
return self.name

class Seller(Base):
childa = models.CharField(max_length=20)

def __unicode__(self):
return u'%s: %s' %(self.name, self.childa)

class Buyer(Base):
childb = models.CharField(max_length=20)
partner = models.ForeignKey(Base, related_name = 'buyer_partner',
blank = True, null = True)

def __unicode__(self):
return u'%s: %s, %s' %(self.name, self.childb, self.partner)

class Item(models.Model):
name = models.CharField(max_length=20)
owner = models.ForeignKey(Base, related_name='item_owner',
blank=True, null=True)

def __unicode__(self):
return u'%s: %s' %(self.name, self.owner)
--- snap ---

I'm using postgresql in the real application and the sqlite3 backend
on this example here, both behave the same.
To add some data I do the following on the python shell (python manage
shell):
--- snip ---
>>> from multi.models import Seller, Buyer, Item, Base
>>> seller = Seller(name='Seller1', childa='ChildA')
>>> seller.save()
>>> buyer = Buyer(name='Buyer1', childb='ChildB', partner=seller)
>>> buyer.save()
>>> item = Item(name='Nice Thing', owner = buyer)
>>> item.save()

--- snap ---

After this I do some query to verify that everything is in the
database (also on the shell):
--- snip ---
>>> from multi.models import Seller, Buyer, Item, Base
>>> Buyer.objects.all()

[<Buyer: Buyer1: ChildB, Seller1>]
>>> Seller.objects.all()

[<Seller: Seller1: ChildA>]
>>> Item.objects.all()

[<Item: Nice Thing: Buyer1>]
--- snap ---

So all necessary data is in the database ... now a few queries to get
data back out and assigned to some vars ... and finally to filter
queries ... the first one is working, the second one seems to bee
'broken' (gives no result = []) and I don't know why ...
--- snip ---
>>> from multi.models import Seller, Buyer, Item, Base
>>> s = Seller.objects.get(name='Seller1')
>>> b = Buyer.objects.get(name='Buyer1')
>>> s

<Seller: Seller1: ChildA>
>>> b

<Buyer: Buyer1: ChildB, Seller1>
>>> Item.objects.filter(owner=b)

[<Item: Nice Thing: Buyer1>]
>>> Item.objects.filter(owner__buyer_partner = s)

[]
--- snap ---

Could anyone point me to the right direction or give me an example how
it is supposed to work?

Regards

Alex

Carl Meyer

unread,
Apr 15, 2011, 11:01:02 AM4/15/11
to django-d...@googlegroups.com
Hi Alex,

If I'm reading this right, I think you're misunderstanding which side of
the relationship related_name applies to. The way you have your models
set up, "buyer_partner" is the name you would use to traverse from the
partner targeted by the "partner" FK back to the Buyer containing that
FK. To traverse from the Buyer to its partner, you would just use
"partner" (the name of the FK) not "buyer_partner" (the related_name).

The owner of your Item is your Buyer, so trying to filter by
owner__buyer_partner is using the wrong name; I would expect
owner__partner=s to work.

If the Item was owned by the Seller in this example, then I would expect
a filter on owner__buyer_partner=b to return the item.

Carl

robim42

unread,
Apr 18, 2011, 3:44:44 AM4/18/11
to Django developers
Hi Carl,

thank you for your answer. I also thought that owner_partner should
work ... but when you try you get this:

>>> from multi.models import Seller, Buyer, Item, Base
>>> s = Seller.objects.get(name='Seller1')
>>> b = Buyer.objects.get(name='Buyer1')
>>> Item.objects.filter(owner__partner=s)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/alex/alex/django-1.2.x/django/db/models/manager.py",
line 141, in filter
return self.get_query_set().filter(*args, **kwargs)
File "/Users/alex/alex/django-1.2.x/django/db/models/query.py", line
561, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/Users/alex/alex/django-1.2.x/django/db/models/query.py", line
579, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/Users/alex/alex/django-1.2.x/django/db/models/sql/query.py",
line 1170, in add_q
can_reuse=used_aliases, force_having=force_having)
File "/Users/alex/alex/django-1.2.x/django/db/models/sql/query.py",
line 1058, in add_filter
negate=negate, process_extras=process_extras)
File "/Users/alex/alex/django-1.2.x/django/db/models/sql/query.py",
line 1237, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'partner' into field. Choices are:
buyer, buyer_partner, id, item_owner, name, seller

Which lead me to the conclusion that I have to use buyer_partner (the
related name) to get what I want (which is: all Items which habe been
bought by any buyer having partner s as a partner).

If I do a print query on the original filter, I get the following,
which seems not right to me:

>>> print Item.objects.filter(owner__buyer_partner = s).query
SELECT "multi_item"."id", "multi_item"."name", "multi_item"."owner_id"
FROM "multi_item" INNER JOIN "multi_base" ON ("multi_item"."owner_id"
= "multi_base"."id") INNER JOIN "multi_buyer" ON ("multi_base"."id" =
"multi_buyer"."partner_id") WHERE "multi_buyer"."base_ptr_id" = 2


Regards

Alex

Carl Meyer

unread,
Apr 18, 2011, 11:51:35 AM4/18/11
to django-d...@googlegroups.com
Hi Alex,

On 04/18/2011 02:44 AM, robim42 wrote:
> thank you for your answer. I also thought that owner_partner should
> work ... but when you try you get this:

Sorry, not owner__partner - since partner is only a field on Buyer, not
on Base, you'd need owner__buyer__partner.

In any case, I don't see any evidence of a bug in Django here (we've got
a pretty good test suite for filter traversal and inheritance), so this
thread should move to django-users.

Carl

Reply all
Reply to author
Forward
0 new messages