2016-03-02 124 views
0

我建立了一個系統來審查葡萄酒和食物。我很快發現自己重複模型和模板,但差異很小。Django在另外兩個人之間共享一個模型

從根本上看,我想要一個審查,以涉及食品或葡萄酒。每種食物或葡萄酒都可以有很多評論。

我有一個FK(目前的方式),只留下一個空白,但鑑於他們如此相似,我決定這不是明智的。

然後,我去了抽象模型,至少能夠字段化字段(新方法),但是因爲我無法鏈接到通用項目模型,所以對於同一個問題我有一個稍微優雅的代碼庫。

研究到這我想知道從食品和葡萄酒到審查的一般關係是要去的方式或內容類型,但我不明白他們如何工作,或者如果他們是我是什麼尋找。

電流的方式 - 葡萄酒有品牌,食品都有專賣店和評論有食品和葡萄酒

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

新途徑 - 葡萄酒和食品的物品,商店和專賣店的來源,但評論仍需要兩葡萄酒和食品

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

回答

1

我覺得Generic Foreign Key就是答案。例如:

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') 

這使我們可以將審閱與項目中任何模型的任何單個記錄相關聯。 content_type字段跟蹤您嘗試關聯的模型(在這種情況下爲FoodWine)。 object_id現場跟蹤記錄在我們試圖跟蹤的WineFood表中。 content_object是一個便利的屬性,允許我們直接訪問對象(一旦保存了評論)。

當創建一個新的檢視剛分配WineFoodcontent_object領域:

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

環顧四周後,我不能做以下(從http://stackoverflow.com/questions取/ 20895429 /如何,究竟-DO-Django的內容類型工作): 評論= generic.GenericRelation( '審覈') 至於可用性。我還會查找給定葡萄酒的評論(使用某種我不太明白的助手)......這是否有用? 即在模板{%for wine.review_set中進行評論。所有%} – Ewanw

+0

{%for wine.reviews.all%}以及我所能想到的每一個變化都不再有效:/ – Ewanw

1

你也可以爲Item使用Multi-table inheritance代替AbstractClass的。然後你可以在Review中設置一個直接ForeignKeyItem。 您還可以結合InheritanceManager此:

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

然後你就可以過濾這樣的:

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() 
+0

我認爲這是一個非常酷的技術,我可以看到它在我想要的東西更多'OO '但通過抽象類的簡單繼承足以讓我的代碼重用 – Ewanw

相關問題