Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django - What are the alternatives to having a ForeignKey to an abstract class?

I want to have an abstract Company model in Django, and extend it depending on the type of the company involved:

class Company(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

    class Meta:
        abstract = True

class Buyer(Company):
    # Buyer fields..
    pass

class Seller(Company):
    # Seller fields...
    pass

Every user on the system is associated with a company, so I want to add the following to the User profile:

company = models.ForeignKey('Company')

But this gives the dreaded error:

main.Profile.company: (fields.E300) Field defines a relation with model 'Company', which is either not installed, or is abstract.

So I imagine what I'm trying to do cannot be done. I saw that the contenttypes framework could be used for this purpose, as answered in this question. My issue with that is that I don't want the company field to point to any model, but just subclasses of the Company model.

Is there anything else I can use for this purpose?

like image 283
user1496984 Avatar asked Sep 14 '25 14:09

user1496984


1 Answers

The reason the ForeignKey cannot reference an abstract model directly is that individual models that inherit from the abstract model actually have their own tables in the database.

Foreign keys are simply integers referencing the id from the related table, so ambiguity would be created if a foreign key was related to an abstract model. For example there might be be a Buyer and Seller instance each with an id of 1, and the manager would not know which one to load.

Using a generic relation solves this problem by also remembering which model you are talking about in the relationship.

It does not require any additional models, it simply uses one extra column.

Example -

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey

class Foo(models.Model):
  company_type = models.ForeignKey(ContentType)
  company_id = models.PositiveIntegerField()
  company = GenericForeignKey('company_type', 'company_id')

And then -

>>> seller = Seller.objects.create()
>>> buyer = Buyer.objects.create()
>>> 
>>> foo1 = Foo.objects.create(company = seller) 
>>> foo2 = Foo.objects.create(company = buyer) 
>>> 
>>> foo1.company 
<Seller: Seller object>
>>> foo2.company 
<Buyer: Buyer object>
like image 132
metahamza Avatar answered Sep 17 '25 05:09

metahamza