frlan
frlan

Reputation: 7270

How to define a foreign key relation with an abstract model?

Having this code:

class Part:
    name = models.CharField(
        _("Name of part"),
        max_length=255,
        help_text=_("Name of the part.")

    class Meta:
        verbose_name = _("Part")
        verbose_name_plural = _("Parts")
        abstract = True


class Book(Part):
    isbn = models.CharField(
        help_text=_("The ISBN of the book"),
        max_length=15
    )

for my models. I next step I need to link to the basic object. Done with this code:

class StorageItem(models.Model):
    part = models.ForeignKey(
        Part,
        help_text=_("The part stored at this spot.")
    )

I'm getting this error message:

ERRORS: StorageItem.part: (fields.E300) Field defines a relation with model 'Part', which is either not installed, or is abstract.

What is the correct approach to link an object to a group of different classes all derived from one base class?

Upvotes: 1

Views: 501

Answers (1)

Derek Kwok
Derek Kwok

Reputation: 13078

Unfortunately it's not possible to add ForeignKeys to abstract models. One way to get around this limitation is to use GenericForeignKey:

class StorageItem(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

Then you can use the GenericForeignKey as follows:

book = Book.objects.create(name='test', isbn='-')
item = StorageItem(content_object=book)
item.save()
item.content_object # <Book>

A quick explanation of how this works:

  • content_type stores the model that generic foreign key points to
  • object_id stores the id of the model
  • content_object is a shortcut for directly accessing the linked foreign key object

The docs provide additional information on how to use this https://docs.djangoproject.com/en/1.9/ref/contrib/contenttypes/#generic-relations

Edit

Upon further research, it looks like django_polymorphic may also do what you want.

Upvotes: 1

Related Questions