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.