2015-05-20 9 views
7

Ich habe dieses Modell:ForeignKey Feld abstraktes Modell in Django Zusammenhang

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

    class Meta: 
     abstract = True 


class ModelA(BaseModel): 
    .... 

class ModelB(BaseModel): 
    .... 


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

Aber das ist nicht richtig, weil ich BaseModel wie Abstract haben. Infact Ich habe einen Fehler, wenn ich makemigration Befehl versuchen.

Der Fehler ist:

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

Gibt es eine Möglichkeit, um ein abstraktes Basismodell zu benutzen?

Ich habe auch versucht zu verwenden:

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

Antwort

6

Es ist nicht möglich, Fremdschlüssel zu abstrakten Modelle in Django zu installieren. Sie können jedoch Fremdschlüssel zu einer nicht abstrakten Basisklasse installieren. Die einzige Einschränkung besteht darin, dass die umgekehrte Fremdschlüsselbeziehung die Basisklasseninstanzen zurückgibt. Sie können diese Einschränkung umgehen, indem Sie django-polymorphic verwenden.

Django Polymorphe können Sie die Basisklasse Objekte abzufragen, sondern ruft die Kindklasse Instanzen:

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

verwenden django polymorphen Sie brauchen nur Ihre Modelle mit Polymorphe Modell als Basisklasse zu deklarieren:

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) 

Fremdschlüssel wird auch die untergeordneten Instanzen der Klasse zurückkehren, das ist, was Sie brauchen, nehme ich an:

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

Berücksichtigen Sie, dass diese Abfragen slightly less performant sind.

+0

Ich wusste nicht PolymorphicModel ... wahrscheinlich kann mir das helfen. Ich verstehe keinen Aspekt: ​​PolymorphicModel basiert auf GenericRelation? Wann ist es notwendig, GenericRelation (content-type) anstelle von PolymorphicModel zu verwenden? Wahrscheinlich ist diese Frage außerhalb des Kontexts meiner ursprünglichen Frage ... – Safari

+1

Generische Relationen sind nicht verwandt mit polymorphen Modellen. Generische Beziehungen sind nützlich für die Art von generischem Modell, das Sie in Ihren Anwendungen haben und die Fremdschlüssel für grundlegend unterschiedliche Modelle haben. Ich habe ein generisches Bildmodell in meiner Anwendung, und beide Event- und Teammodelle können Bilder haben. Dies ist eine generische Beziehung. Ich habe auch ein InternationalTeam-Modell, das von Team erbt, und dann haben Teams auch Bilder, ohne dass ich das explizit im Modell angeben muss. –

3

Wenn ich wie eine Situation konfrontiert, dass, wo ich zu Foreign verschiedene Modelle machen wir wählen GenericForeignKey verwenden, können Sie hier offizielle Dokumente überprüfen: Django ContentTypes: Generic Relations

die docs erklären recht gut, wie es zu benutzen:

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 
  • Das Feld content_type speichern das Modell, das die allgemeine Fremdschlüssel verweist auf

  • Das Feld object_id speichern die ID des Fremdschlüssels,

  • Das Feld content_object Sie hilft den direkten Zugriff auf das damit verbundene Objekt basierend auf den anderen zwei Feldern

es ist nicht die beste Lösung, aber es spart mich in einigen Projekten

Beispiel der Verwendung es:

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

von der nette Antwort Abgesehen mit GenericForeignKey, mit denen ich nicht ganz vertraut bin, manchmal (nur manchmal, wenn möglich), lohnt es sich Ihre Modelle mit unter Verwendung von Ein- vereinfachen off Eins-zu-eins-Beziehungen zu Ihrem Basismodell.

Macht Fremdschlüssel-Management einfacher danach. Wenn ich mich gut erinnere, ist ein Fremdschlüssel in einer abstrakten Klasse nicht möglich.