Django, der ein Modell zwischen zwei anderen teilt

Ich habe ein System gebaut, um Weine und Lebensmittel zu überprüfen. Ich habe mich schnell wiedergegeben, um Modelle und Vorlagen mit winzigen Unterschieden zu wiederholen.

Grundsätzlich scheint es, dass ich eine Überprüfung auf ein Essen oder einen Wein beziehen möchte. Und jedes Essen oder Wein kann viele Kritiken haben.

Ich hatte eine FK (aktueller Weg) zu beiden und ließ einfach eine leere, aber wenn sie so ähnlich war, entschied ich, dass war nicht klug.

Ich ging dann zu abstrakten Modellen, um zumindest die Felder zu generieren (neuer Weg), aber da konnte ich nicht mit dem generischen Artikelmodell verknüpfen, hatte ich eine etwas elegantere Codebasis für das gleiche Problem.

Erforschung dieses Ich frage mich, ob eine generische Beziehung von der Nahrung und Wein zur Überprüfung ist der Weg zu gehen oder vielleicht Content-Typen, aber ich weiß nicht ganz, wie sie arbeiten oder wenn sie sind, was ich suche.

Gegenwärtiger Weg – Weine haben Marken, Lebensmittel haben Läden und Bewertungen haben Lebensmittel und Weine

class Brand(models.Model): brand_name = models.CharField(max_length=30) location = models.ForeignKey(Location, null=True,blank=True) import datetime YEAR_CHOICES = [] for r in range(2005, (datetime.datetime.now().year+1)): YEAR_CHOICES.append((r,r)) YEAR_CHOICES = list(reversed(YEAR_CHOICES)) class Wine(models.Model): wine_name = models.CharField(max_length=30) wine_type = models.ForeignKey(WineType) wine_year = models.IntegerField( choices=YEAR_CHOICES, default=datetime.datetime.now().year) brand = models.ForeignKey(Brand) class Store(models.Model): store_name = models.CharField(max_length=30) def __str__(self): return self.store_name class Food(models.Model): food_name = models.CharField(max_length=30) food_desc = models.CharField(blank=True,max_length=100) store = models.ForeignKey(Store) def __str__(self): return self.store.store_name +' - '+self.food_name class Review(models.Model): rating = models.CharField(max_length=30) value = models.CharField(max_length=30) date = models.DateField(auto_now_add=True) person = models.ForeignKey(Person) comment = models.CharField(blank=True,max_length=100) food = models.ForeignKey(Food, blank=True,default=None,null=True) wine = models.ForeignKey(Wine, blank=True,default=None,null=True) class Meta(): ordering = ['-date'] 

New Way – Weine und Lebensmittel sind Gegenstände, Stores und Marken sind Quellen, aber Bewertungen müssen noch Weine und Lebensmittel

 class Source(models.Model): name = models.CharField(max_length=30) desc = models.CharField(blank=True,max_length=100) class Meta: abstract = True class Item(models.Model): name = models.CharField(max_length=30) desc = models.CharField(blank=True,max_length=100) class Meta: abstract = True class WineSource(Source): location = models.ForeignKey(Location, null=True,blank=True) class Meta(): ordering = ['location', 'name'] class FoodSource(Source): def __str__(self): return self.name import datetime YEAR_CHOICES = [] for r in range(2005, (datetime.datetime.now().year+1)): YEAR_CHOICES.append((r,r)) YEAR_CHOICES = list(reversed(YEAR_CHOICES)) class Wine(Item): wine_type = models.ForeignKey(WineType) wine_year = models.IntegerField( choices=YEAR_CHOICES, default=datetime.datetime.now().year) source = models.ForeignKey(WineSource) def __str__(self): return self.source.name +' '+self.name+ ' ' + str(self.wine_type)+ ' '+ str(self.wine_year) class Food(Item): source = models.ForeignKey(FoodSource) def __str__(self): return self.source.name +' - '+self.name class Review(models.Model): rating = models.CharField(max_length=30) value = models.CharField(max_length=30) date = models.DateField(auto_now_add=True) person = models.ForeignKey(Person) food = models.ForeignKey(Food, blank=True,default=None,null=True) wine = models.ForeignKey(Wine, blank=True,default=None,null=True) #Doesn't work as it's abstract- item = models.ForeignKey(Item,null=True) class Meta(): ordering = ['-date'] 

2 Solutions collect form web for “Django, der ein Modell zwischen zwei anderen teilt”

Ich denke, Generic Foreign Key ist die Antwort. Etwas wie:

 from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class Product(models.Model): ... class Food(Product): ... class Wine(Product): ... class Review(models.Model): ... content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') 

Dies ermöglicht es uns, eine Rezension zu jedem einzelnen Datensatz eines Modells in unserem Projekt zu verknüpfen. Die content_type , welche Modell Sie versuchen, sich zu beziehen ( Food oder Wine in diesem Fall). Die object_id , die in der Wine oder Food aufzeichnen, versuchen wir zu verfolgen. content_object ist ein Bequemlichkeitsattribut, das uns einen direkten Zugriff auf das Objekt ermöglicht (sobald die Überprüfung gespeichert wurde).

Bei der Erstellung einer neuen Rezension vergeben Sie dem Feld " content_object einfach den Wine oder das Food :

 wine = Wine.objects.get(...) review = Review(..., content_object=wine) review.save() 

Sie können auch Multi-Table-Vererbung anstelle einer AbstractClass für Item . Dann können Sie einen direkten ForeignKey auf Item in Review . Sie können das auch mit InheritanceManager kombinieren:

 from model_utils.managers import InheritanceManager class Item(models.Model): name = models.CharField(max_length=30) desc = models.CharField(blank=True,max_length=100) objects = InheritanceManager() class Wine(Item): wine_type = models.ForeignKey(WineType) wine_year = models.IntegerField( choices=YEAR_CHOICES, default=datetime.datetime.now().year) source = models.ForeignKey(WineSource) def __str__(self): return self.source.name +' '+self.name+ ' ' + str(self.wine_type)+ ' '+ str(self.wine_year) class Food(Item): source = models.ForeignKey(FoodSource) def __str__(self): return self.source.name +' - '+self.name class Review(models.Model): rating = models.CharField(max_length=30) value = models.CharField(max_length=30) date = models.DateField(auto_now_add=True) person = models.ForeignKey(Person) item = models.ForeignKey(Item,null=True) class Meta(): ordering = ['-date'] 

Dann können Sie so filtern:

 wine_reviews = Review.objects.exclude(item__wine__isnull=True) food_reviews = Review.objects.exclude(item__food__isnull=True) # and all item (directly sub-classed as wine or food: items = Item.objects.select_subclasses().all() 
  • Django - Entwerfen von Modellen mit virtuellen Feldern?
  • Verwenden von Modellen und Formen außerhalb von Django?
  • Itering durch Modellfelder - Django
  • Django Form Preview - Wie man mit 'cleaned_data' arbeitet
  • Wie bekomme ich den Namen des Modells oder den Inhaltstyp eines Django-Objekts?
  • Django-Modellunterklassen: Holen Sie sich die Unterklasse, indem Sie die Superklasse abfragen
  • TypeError: int () - Argument muss ein String oder eine Zahl sein, nicht 'Model Instance'
  • Django, Postgres - Spalte kann nicht automatisch gegossen werden, um Integer zu schreiben
  • Django - Site-Matching-Abfrage existiert nicht
  • Increment Page Hit Count in Django
  • Django-Modell: Filterung durch Benutzer, immer
  • Python ist die beste Programmiersprache der Welt.