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

+2


source to share


3 answers


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 (including related_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()

      

+7


source


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?

+2


source


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)

      

+1


source







All Articles