Skip to content Skip to sidebar Skip to footer

Foreignkey Field Related To Abstract Model In Django

I have this model: class BaseModel(models.Model): .... class Meta: abstract = True class ModelA(BaseModel): .... class ModelB(BaseModel): .... class M

Solution 1:

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:         id1, topic "Department Party">,
  <ArtProject:      id2, topic "Painting with Tim", artist "T. Turner">,
  <ResearchProject: id3, 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 models
from polymorphic.models import PolymorphicModel

classModelA(PolymorphicModel):
    field1 = models.CharField(max_length=10)

classModelB(ModelA):
    field2 = models.CharField(max_length=10)

classModelC(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 notclassRelatingModel(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: id1, field1 (CharField)>,
  <ModelB: id2, field1 (CharField), field2 (CharField)>,
  <ModelC: id3, field1 (CharField), field2 (CharField), field3 (CharField)> ]

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

Solution 2:

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 models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

classTaggedItem(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 2return 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 User
guido = User.objects.get(username='Guido')
t = TaggedItem(content_object=guido, tag='bdfl')
t.save()
t.content_object
<User: Guido>

Solution 3:

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.

Post a Comment for "Foreignkey Field Related To Abstract Model In Django"