ForeignKey field related to abstract model in Django ForeignKey field related to abstract model in Django python python

ForeignKey field related to abstract model in Django


It's not possible to install Foreign Keys to abstract models in Django.You can however install Foreign Keys to a non abstract base class. The only limitation is that the reverse Foreign Key relation will return the base class instances.You can circumvent this limitation by using django-polymorphic.

Django Polymorphic allows you to query the base class objects but retrieves the child class instances:

>>> Project.objects.create(topic="Department Party")>>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner")>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")>>> Project.objects.all()[ <Project:         id 1, topic "Department Party">,  <ArtProject:      id 2, topic "Painting with Tim", artist "T. Turner">,  <ResearchProject: id 3, topic "Swallow Aerodynamics", supervisor "Dr. Winter"> ]

To use django polymorphic you only need to declare your models with Polymorphic Model as base class:

from django.db import modelsfrom polymorphic.models import PolymorphicModelclass ModelA(PolymorphicModel):    field1 = models.CharField(max_length=10)class ModelB(ModelA):    field2 = models.CharField(max_length=10)class ModelC(ModelB):    field3 = models.CharField(max_length=10)

Foreign keys will also return the child class instances, which is what you need I assume:

# The model holding the relation may be any kind of model, polymorphic or notclass RelatingModel(models.Model):    many2many = models.ManyToManyField('ModelA')  # ManyToMany relation to a polymorphic model>>> o=RelatingModel.objects.create()>>> o.many2many.add(ModelA.objects.get(id=1))>>> o.many2many.add(ModelB.objects.get(id=2))>>> o.many2many.add(ModelC.objects.get(id=3))>>> o.many2many.all()[ <ModelA: id 1, field1 (CharField)>,  <ModelB: id 2, field1 (CharField), field2 (CharField)>,  <ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]

Take into account that these queries will be slightly less performant.


When I faced a situation like that where I have to make ForeignKeys to different models I choose to use GenericForeignKey you can check official docs here: Django ContentTypes: Generic Relations

The docs explain quite well how to use it:

from django.db import modelsfrom django.contrib.contenttypes.fields import GenericForeignKeyfrom django.contrib.contenttypes.models import ContentTypeclass TaggedItem(models.Model):    tag = models.SlugField()    content_type = models.ForeignKey(ContentType)    object_id = models.PositiveIntegerField()    content_object = GenericForeignKey('content_type', 'object_id')    def __str__(self):              # __unicode__ on Python 2        return self.tag
  • The field content_type store the model that the generic foreign key is pointing to

  • The field object_id store the ID of the foreign key,

  • The field content_object helps you to access directly to the related object based on the other 2 fields

It is not the best solution but it saves me in some projects

Example of using it:

from django.contrib.auth.models import Userguido = User.objects.get(username='Guido')t = TaggedItem(content_object=guido, tag='bdfl')t.save()t.content_object<User: Guido>


Apart from the nice answer with GenericForeignKey, with which I am not quite familiar, sometimes (just sometimes, whenever possible), it pays off to simplify your models with using one-to-one relationships to your 'base' model.

Makes foreign keys management easier after that. If I remember well, foreign key on an abstract class is not possible.