Tengo este modelo:
class BaseModel(models.Model): .... class Meta: abstract = True class ModelA(BaseModel): .... class ModelB(BaseModel): .... class MyExtModel(models.Model) myfield = models.ForeignKey(BaseModel)
Pero esto no es correcto porque tengo BaseModel
como Abstract
. Infact Tengo un error cuando bash el comando makemigration
.
El error es:
ERRORS: myapp.MyExtModel.myfield: (fields.E300) Field defines a relation with model 'BaseModel', which is either not installed, or is abstract.
¿Hay alguna manera de usar un modelo base abstracto?
También traté de usar:
myfield = models.ForeignKey(BaseModel, related_name="%(app_label)s_%(class)s_related")
No es posible instalar claves externas para extraer modelos en Django. Sin embargo, puede instalar claves externas en una clase base no abstracta. La única limitación es que la relación de clave foránea inversa devolverá las instancias de clase base. Puedes sortear esta limitación usando django-polymorphic .
Django Polymorphic le permite consultar los objetos de la clase base, pero recupera las instancias de la clase secundaria:
>>> 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() [ , , ]
Para usar django polymorphic solo necesita declarar sus modelos con Polymorphic Model como clase base:
from django.db import models from polymorphic.models import PolymorphicModel class 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)
Las claves externas también devolverán las instancias de clase secundaria, que es lo que necesita, asumo:
# The model holding the relation may be any kind of model, polymorphic or not class 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() [ , , ]
Tenga en cuenta que estas consultas tendrán un rendimiento ligeramente inferior .
Cuando me enfrenté a una situación como esa en la que tengo que hacer ForeignKeys para diferentes modelos que elijo usar GenericForeignKey
, puedes consultar los documentos oficiales aquí: Django ContentTypes: Relaciones genéricas
Los documentos explican muy bien cómo usarlo:
from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class 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
El campo content_type almacena el modelo al que apunta la clave externa genérica
El campo object_id almacena el ID de la clave externa,
No es la mejor solución pero me salva en algunos proyectos.
Ejemplo de uso:
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
Aparte de la buena respuesta con GenericForeignKey
, con la que no estoy muy familiarizado, a veces (solo algunas veces, siempre que sea posible), vale la pena simplificar sus modelos con el uso de relaciones GenericForeignKey
con su modelo “base”.
Facilita la administración de claves externas después de eso. Si recuerdo bien, la clave externa en una clase abstracta no es posible.