Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use abstract model as a ForeignKey in Django?

I have a model like this:

class A(models.Model):
     ....
     ....
     class Meta:
        abstract = True

class B(A):
     blah..
     blah..

class C(A):
     blah..
     blah..

Just I want to use Model A as a ForeignKey in different model like this:-

class X(models.Model):
       """
       I want to use like this, But i'm getting error
       """
       name = models.ForeignKey(A)

But I'm getting Error:

apis.X.name: (fields.E300) Field defines a relation with model 'A', which is either not installed, or is abstract.

Am I doing something wrong? How can to avoid this?

Thanks in advance

like image 842
Mr Singh Avatar asked Jan 03 '23 04:01

Mr Singh


2 Answers

Setting Abstract=True in your Meta means that no table is created in your database.

From the docs:

Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class. This model will then not be used to create any database table. Instead, when it is used as a base class for other models, its fields will be added to those of the child class.

To resolve your issue, you should Foreign key to either model B or model C since those will represent actual tables in your database. Your abstract model should only be used for inheritance purposes.

like image 97
dfundako Avatar answered Jan 05 '23 14:01

dfundako


Django provides a special field type (GenericForeignKey) which works around this and allows the relationship to be with any model be it a Abstract one.

Refer to GenericForeignKey Docs for more insight on this.

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

class TaggedItem(models.Model):
    tag = models.SlugField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

def __str__(self):
    return self.tag

OR:

You can make implement a custom model into a base model by using abstract = True in it and in your child models you can use it as ForeignKey.

Implementation would be something like this:

class X(models.Model):
   """
   I want to use like this, But i'm getting error
   """
   name = models.ForeignKey(A)
   class Meta:                                                             
       abstract = True                                                     
return A                                                   

For this one goto to abstract-base-classes Docs:

like image 30
ans2human Avatar answered Jan 05 '23 16:01

ans2human