Django model inheritance, filter model
Considering the following models: (ignore TextFields, for illustration purposes only)
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, the Content object can be associated with more than one base object, for example. interview (= Content Object) can be associated with musician (= Child1 object), movie director (= Child2), etc.
Now, on my question: Is it possible to filter content objects according to which model the aso_items field indicates? Example: Let's say I need a Queryset containing all Content objects associated with a specific Child1 object (for example, all interviews related to musician Bob Dylan), how can I achieve this?
Also, what if I want the QuerySet to contain all Content objects associated with Child1 objects? (eg all interviews related to musicians) How will this change filtering?
Thanks in advance ps: I am having issues with the space in the preview, forgive me
source to share
You should check the Django docs section regarding usage 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
related_name
an attribute on a ForeignKey or ManyToManyField, you must always provide a unique reverse name for the field. This is usually a problem in abstract base classes, since the fields of that class are included in every child class with exactly the same values ββfor attributes (includingrelated_name
) every time.To work around this problem, when you use an associated name in an abstract base class (only), the name part must be a string
%(class)s
. This is replaced by the lower name of the child class that is used in the field in. Since each class has a different name, each associated name will end up being different.
Using this information, I would recommend moving the m2m field to 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()
source to share
Apparently a ForeignKey (or ManyToMany for that matter) relationship with an abstract class is not allowed. I am getting the following error: "AssertionError: ForeignKey cannot define relationship with abstract class Artiest".
A possible solution is to define the base class as not abstract, however this means that one could create models of the base class. This is not the behavior I want (it was an abstract class after all) Someone comes across the same problem how you solved it? Any alternatives?
source to share
Have a look at http://www.djangoproject.com/documentation/models/generic_relations/ which goes through general relationships. Your content model will match their TaggedItem model and your base model will match their Animal / Vegetable / Mineral model (with Child1 and Child2 extensions).
Getting all Content objects for one child would be (if you set GenericRelation for content inside Base):
child_contents = childObject.contents.all()
And get all content objects for the model:
ctype = ContentType.objects.get_for_model(Child1)
all_child_contents = Content.objects.filter(content_type=ctype)
source to share