2015-05-20 27 views
7

mam ten model:ForeignKey dziedzinie związanej z teoretycznego modelu w Django

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

    class Meta: 
     abstract = True 


class ModelA(BaseModel): 
    .... 

class ModelB(BaseModel): 
    .... 


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

Ale to nie jest prawidłowe, ponieważ mam BaseModel jak Abstract. Rzeczywiście Mam błąd, gdy próbuję wykonać polecenie makemigration.

Błąd jest:

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

Czy istnieje sposób na wykorzystanie abstrakcyjnego modelu bazowego?

Próbowałem również użyć:

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

Odpowiedz

6

Nie można zainstalować kluczy obcych w modelach abstrakcyjnych w Django. Można jednak zainstalować klucze obce na nie abstrakcyjną klasę podstawową. Jedynym ograniczeniem jest to, że odwrotna relacja klucza obcego zwróci instancje klasy podstawowej. Można obejść to ograniczenie, używając django-polymorphic.

Django polimorficzne pozwala na zapytanie obiektów klasy bazowej, ale pobiera instancje klasy dziecko:

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

używać Django polimorficzny wystarczy zadeklarować swoje modele z polimorficzna modelu jako klasy bazowej:

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) 

klucze obce będą również zwracać instancje klasy dziecko, co jest, co trzeba Przypuszczam:

# 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)> ] 

Należy wziąć pod uwagę, że zapytania te będą slightly less performant.

+0

Nie znałem PolymorphicModel ... prawdopodobnie to może mi pomóc. Nie rozumiem jednego aspektu: PolymorphicModel opiera się na GenericRelation? Kiedy należy użyć GenericRelation (typ zawartości) zamiast PolymorphicModel? Prawdopodobnie to pytanie jest poza kontekstem mojego pierwotnego pytania ... – Safari

+1

Relacje ogólne nie są powiązane z modelami polimorficznymi. Relacje generyczne są przydatne dla rodzaju ogólnego modelu, który masz w swoich aplikacjach i które mają klucze obce dla zasadniczo różnych modeli. Mam ogólny model obrazu w mojej aplikacji, a modele zdarzeń i zespołów mogą mieć obrazy. To jest ogólny związek. Posiadam również model InternationalTeam, który dziedziczy po Zespole, a następnie także Teamy będą miały Obrazy, bez konieczności określania tego wyraźnie w modelu. –

3

Kiedy w obliczu takiej sytuacji, gdzie mam zrobić ForeignKeys do różnych modeli wybrałbym korzystać GenericForeignKey można sprawdzić oficjalne dokumenty tutaj: Django ContentTypes: Generic Relations

docs wyjaśnić dość dobrze, jak go używać:

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 
  • Pole content_type sklep model, który rodzajowy klucz obcy jest skierowany do

  • dziedzinie object_id przechowywać identyfikator klucza obcego,

  • Pole content_object pozwala na bezpośredni dostęp do związany z nim obiekt na podstawie innych 2 pól

to nie jest najlepszym rozwiązaniem, ale ratuje mnie w niektórych projektach

Przykład wykorzystania go:

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

Oprócz miłej odpowiedzi z GenericForeignKey, z którym nie jestem dość dobrze, czasami (tylko czasami, gdy jest to możliwe), to opłaca się uprościć swoje modele z użyciem jedno- do jednego związku z twoim modelem "podstawowym".

Umożliwia późniejsze zarządzanie kluczami obcymi. Jeśli dobrze pamiętam, klucz obcy na klasie abstrakcyjnej nie jest możliwy.