Given the following models:(don't mind the TextFields there're just for illustration)
class Base(models.Model): field1 = models.TextField() class Meta: abstract=True class Child1(Base): child1_field = models.TextField() class Child2(Base): child2_field = models.TextField() class Content(models.Model): aso_items = models.ManyToManyField('Base')
According to these definitions a Content object can be associated with more than one Base object, eg. an interview(=Content object) can be linked with a musician(=Child1 object), a filmdirector(=Child2), etc.
Now, for my question: Is it possible to filter Content objects according to which model the aso_items field points to? An example : Say I would like a Queryset containing all the Content objects that are associated with a specific object of Child1(eg. all the interviews associated with the musician Bob Dylan), how can I achieve this?
Further, what if I'd want a QuerySet containing all the Content objects that are associated with Child1 objects?(eg. all the interviews that associated with musicians) How does this change the filtering?
Thanks in advance ps: I'm experiencing some problems with white space in the preview, forgive me
You should check the section of the Django docs regarding using
related_name for abstract base classes. http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name
To quote the docs:
If you are using the
attribute on a ForeignKey or
ManyToManyField, you must always
specify a unique reverse name for the
field. This would normally cause a
problem in abstract base classes,
since the fields on this class are
included into each of the child
classes, with exactly the same values
for the attributes (including
related_name) each time.
To work around this problem, when you
are using related_name in an abstract
base class (only), part of the name
should be the string
is replaced by the lower-cased name of
the child class that the field is used
in. Since each class has a different
name, each related name will end up
Using this information I would recommend moving the m2m field into the Base class:
class Content(models.Model): # Add remaining fields for Content pass class Base(models.Model): field1 = models.TextField() items = models.ManyToManyField(Content,related_name="%(class)s_related") class Meta: abstract=True class Child1(Base): child1_field = models.TextField() class Child2(Base): child2_field = models.TextField()
Apparently a ForeignKey relation(or ManyToMany for that matter) with a abstract class isn't allowed. I get the following error : 'AssertionError: ForeignKey cannot define a relation with abstract class Artiest'.
A possible solution is to define the base class as non-abstract, however this implies that one could instantiate models of the base class. Which isn't the behavior I want.(after all it was an abstract class) Has someone come accross the same problem how did you solve it? Any alternatives?
Have a look at http://www.djangoproject.com/documentation/models/generic_relations/ which goes through generic relations. Your Content model would match up to their TaggedItem model, and your Base model would match up to their Animal/Vegetable/Mineral model (with Child1 and Child2 extending).
Getting all of the Content objects for a single child would be (assuming you set the GenericRelation to contents inside Base):
child_contents = childObject.contents.all()
And to get all Content objects for a model:
ctype = ContentType.objects.get_for_model(Child1) all_child_contents = Content.objects.filter(content_type=ctype)