2015-05-20 5 views
7

У меня есть эта модель:ForeignKey поля, связанные с абстрактной модели в Django

class BaseModel(models.Model): 
    .... 

    class Meta: 
     abstract = True 


class ModelA(BaseModel): 
    .... 

class ModelB(BaseModel): 
    .... 


class MyExtModel(models.Model) 
    myfield = models.ForeignKey(BaseModel) 

Но это не правильно, потому что у меня есть BaseModel как Abstract. Infact У меня есть ошибка, когда я пытаюсь выполнить команду makemigration.

Ошибка:

ERRORS: 
myapp.MyExtModel.myfield: (fields.E300) Field defines a relation with model 'BaseModel', which is either not installed, or is abstract. 

Есть ли способ использовать абстрактную базовую модель?

Я также попытался использовать:

myfield = models.ForeignKey(BaseModel, related_name="%(app_label)s_%(class)s_related") 

ответ

6

Невозможно установить внешние ключи для абстрактных моделей в Django. Однако вы можете установить внешние ключи для не абстрактного базового класса. Единственное ограничение заключается в том, что обратное отношение внешнего ключа вернет экземпляры базового класса. Вы можете обойти это ограничение, используя django-polymorphic.

Джанго Полиморфные позволяет запрашивать объекты базового класса, но получают экземпляры класса ребенка:

>>> 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"> ] 

Чтобы использовать Джанго полиморфные вам нужно только объявить свои модели с полиморфной моделью в качестве базового класса:

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) 

Внешние ключи также будут возвращать экземпляры класса ребенка, который является то, что вам нужно я предполагаю:

# 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() 
[ <ModelA: id 1, field1 (CharField)>, 
    <ModelB: id 2, field1 (CharField), field2 (CharField)>, 
    <ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ] 

Учтите, что эти запросы будут slightly less performant.

+0

Я не знал ПолиморфизмМодель ... возможно, это может мне помочь. Я не понимаю один аспект: PolymorphicModel основан на GenericRelation? Когда необходимо использовать GenericRelation (content-type) вместо PolymorphicModel? Вероятно, этот вопрос выходит за рамки моего первоначального вопроса ... – Safari

+1

Общие отношения не связаны с полиморфными моделями. Общие отношения полезны для типовой модели, которую у вас есть в ваших приложениях, и которые имеют внешние ключи для принципиально разных моделей. У меня есть общая модель Image в моем приложении, и у моделей Event и Team могут быть изображения. Это общие отношения. У меня также есть модель InternationalTeam, которая наследуется от Team, а затем также команды будут иметь Images, без необходимости указывать это явно в модели. –

3

Когда я столкнулась с ситуацией, как и где я должен сделать ForeignKeys для разных моделей я выбираю использовать GenericForeignKey вы можете проверить официальные документы здесь: Django ContentTypes: Generic Relations

Документы объяснить довольно хорошо, как использовать его:

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 
  • Поле content_type магазин модель, общий внешний ключ указывает на

  • Поле object_id магазин идентификатор внешнего ключа,

  • Поле content_object позволяет получить прямой доступ к связанный с этим объектом, основанный на других 2-х полей

это не лучшее решение, но это спасает меня в некоторых проектах

Пример его использования:

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> 
1

Помимо прекрасного ответа с GenericForeignKey, с которым я не совсем знаком, иногда (только иногда, когда это возможно), это окупается, чтобы упростить ваши модели с помощью одно- к-одному к вашей «базовой» модели.

После этого упрощает управление внешними ключами. Если я хорошо помню, внешний ключ в абстрактном классе невозможен.

Смежные вопросы