24
I’m trying to make a query in Django with several joins, and I came across this mistake that I don’t know what it means:
Tag.objects.filter(dset__descendant__entities__entity=e)
Fielderror: Relation Fields do not support nested lookups
My models on this query sane Tag, Entity, TaggedEntity and EntityClosure (is an EAV model, full code here). They represent the following:
Entityis an entity. All it has are "name" and "details":class Entity(models.Model): name = models.TextField(null=True, blank=True, default=None) details = models.TextField(null=True, blank=True, default=None)EntityClosureis a table of relationships (entities form a tree):class EntityClosure(Model): ancestor = models.ForeignKey(Entity, related_name="dset") descendant = models.ForeignKey(Entity, related_name="aset") depth = models.PositiveSmallIntegerField()Tagis a "tag" associated with an entity. Each entity can have multiple tags, and the tags themselves are entities (i.e. they also form a tree):class Tag(Entity): pass class TaggedEntity(Model): entity = models.ForeignKey(Entity,related_name="tags") tag = models.ForeignKey(Tag,related_name="entities")
My query desired is: "select all tags associated with an entity"...
Tag.objects.filter(entities__entity=e) # Funciona
..."but taking into account the hierarchy" (i.e. also search for tags that are ancestors of tags associated with the entity):
Tag.objects.filter(dset__descendant__entities__entity=e) # Erro
I don’t see anything wrong with this query... but some problem is happening between the descendant and the entities which does not allow it to be done. The strange thing is that if I do two queries he accepts in a good:
>>> conj = [x.ancestors for x in Tag.objects.filter(entities__entity=d).annotate(ancestors=F('aset__ancestor'))]
>>> conj
[3, 1, 3, 1]
>>> Tag.objects.filter(pk__in=conj)
[<Tag: TipoDocumento>, <Tag: Recibo Fiscal>]
Here is a MCVE, if you want to test (the actual code is much more extensive).
Note also that - as this example in Sqlfiddle shows - the query I want to do is nothing big, I just don’t know why Django is having trouble putting it together:
select t.*
from tagged_entity te
join entity_closure ec on te.tag = ec.descendant
join entity t on t.id = ec.ancestor
where te.entity = 1;
So... what does this mean FieldError presented, and how can I bypass it to do what I want with a single query?
Updating: after upgrading to Django 1.11 the error message has changed:
Fielderror: Related Field got invalid lookup: entities
Which is a bit more descriptive than the previous message. Possibly the error is in using __entities - a relationship of Tag - shortly after __descendant - a relationship of EntityClosure - since EntityClosure does not relate to Tag, but rather with Entity. This would also explain why the two-way solution works: because the result of the first would be a set of entities, not of tags...

You’re trying to access
dsetdirectly fromTagno relationship, or I’m wrong?– Paulo
@Orion I don’t understand.
dsetis therelated_namecountryEntityClosure.ancestor. I can access it normally (ex.:Tag.objects.filter(dset__descendant=4)returns all id tag ancestors4). The problem is between thedescendantand theentitiesaccording to my tests, but I could be wrong.– mgibsonbr
I didn’t know that inheriting created this relationship, so I wondered.
– Paulo
@Orion Yes. From what I could see, if a model
Taginherits from a modelEntity, then the table representing the tag will have instead of a fieldid, a fieldentity_ptror something like that, which is both a primary key and a foreign key to the mother table. Thus, all relations of other tables with the mother table are also applicable to the child model, since it is represented by a row in the mother table and a row in the daughter table (having all columns of both), with the same primary key.– mgibsonbr
@mgibsonbr, reading the last comment on the creation of the mother table, if you did not want this table to be created, you should put a Meta class: Abstract = True in Entity. In this case Django does not create the mother table and all fields of it would be in the tag table in your case. This would decrease the number of joins to be made. But I would have to review the modeling in Entityclosure that has the foreignkey for Entity
– Puam Dias
@Puamdias Unfortunately it is important to me that the Entity table exists (because it is elements of it that will receive the tag). And anyway my goal is not to reduce the number of joins (my real query has even more joins rsrs), but to solve this problem of not being able to mount the query. If I have no solution, beauty, I can live with two queries instead of one, but the ideal would be to make the whole query in one query (and as you can see in the example SQL, it is nothing of the other world...).
– mgibsonbr