views:

433

answers:

1

I'm trying to create a mapping table between two generic (content_type) references, one for "agents" and one for "resources".

So I take the usual way I make a generic foreign key :

content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
resource = generic.GenericForeignKey('content_type', 'object_id')

And I try to make a model with two.

agent_content_type = models.ForeignKey(ContentType)
agent_object_id = models.PositiveIntegerField()
agent = generic.GenericForeignKey('agent_content_type', 'agent_object_id')

resource_content_type = models.ForeignKey(ContentType)
resource_object_id = models.PositiveIntegerField()
resource = generic.GenericForeignKey('resource_content_type', 'resource_object_id')

But this now throws up the following errors :

myapp.mymodel: Accessor for field 'resource_content_type' clashes with related field 'ContentType.mymodel_set'. Add a related_name argument to the definition for 'resource_content_type'.

And similar for the agent.

What's going on here? And what should I do?

cheers

phil

+3  A: 

Have you tried doing what the error message tells you to do - add a related_name argument?

agent_content_type = models.ForeignKey(ContentType, related_name='mymodel_agent')

Edit: The reason why it happens is that every time you define a foreign key, Django automatically gives the target model an attribute to do the reverse lookup. By default, it gives this the name of the related table + '_set' - so if your article table has an FK to section, section will get an article_set attribute for the reverse lookup.

Now if you have two FKs in the same model pointing at the same target model, Django will try and give them both the foo_set attribute, leading to a collision. Hence the error message, which tells you to set the related_name attribute manually.

Daniel Roseman
thanks, that works. But I was hoping someone could explain why. Or rather, why the ambiguity appears when I have two generic foreign keys but not one?
interstar
Edited to add the explanation.
Daniel Roseman