Django在两个人之间分享一个模型 [英] Django sharing one model between two others

查看:90
本文介绍了Django在两个人之间分享一个模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立了一个审查葡萄酒和食品的系统。我很快发现自己重复的模型和模板有微小的差异。



从根本上说,我想要一个关于食物或葡萄酒的评论。每个食物或葡萄酒都可以有很多评论。



我有两个FK(当前的方式),只剩下一个空白,但是由于他们很相似,我决定不是明智的。



然后,我去抽象模型至少生成字段(新方法),但是我无法链接到我拥有的通用项目模型对于同样的问题,一个稍微更优雅的代码库。



研究这个我想知道从食物和葡萄酒到审查的一般关系是如何走或者可能是内容类型,但我不太了解他们的工作方式,或者他们是否正在寻找。



目前的方式 - 葡萄酒有品牌,食物有商店和评论有食物和葡萄酒

  class品牌(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,(datetim e.datetime.now()。year + 1)):
YEAR_CHOICES.append((r,r))
YEAR_CHOICES =列表(反转(YEAR_CHOICES))

类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(品牌)

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_len gth = 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 WineSour ce(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(revers(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食物(物品):


source = models.ForeignKey(FoodSource)

def __str __(self):
return self.source.na me +' - '+ 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, = None,null = True)
wine = models.ForeignKey(Wine,blank = True,default = None,null = True)
#不工作,因为它的abstract- item = models.ForeignKey item,null = True)

class Meta():
ordering = ['-date']


解决方案

我认为通用外键是答案。如下:

  from django.db import models 
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class Product(models.Model):
...

class食物(产品):


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 字段跟踪您尝试关联的模型(食物 Wine 在这种情况下)。 object_id 字段跟踪 Wine 食物中的哪个记录我们正在尝试跟踪的表。 content_object 是一个方便的属性,允许我们直接访问对象(一旦保存了评论)。



创建新评论时,您只需将 Wine 食物分配给 content_object field:

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


I built a system to review wines and foods. I quickly found myself repeating models and templates with tiny differences.

Fundamentally it seems I want a review to relate to either a food or a wine. And each food or wine can have many reviews.

I had an FK (current way) to both and just left one blank but given they're so similar I decided that wasn't wise.

I then went to abstract models to at least generify the fields (new way) but as I couldn't link to the generic item model I had a slightly more elegant code base for the same problem.

Researching into this I'm wondering if a generic relation from the food and wine to the review is the way to go or maybe content types but I don't get quite how they work or if they are what I'm looking for.

Current way - Wines have brands, Foods have stores and Reviews have Foods and wines

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 - Wines and Foods are Items, Stores and Brands are Sources, but reviews still need both Wines and foods

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

解决方案

I think Generic Foreign Key is the answer. Something like:

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

This allows us to relate a review to any single record of any model in our project. The content_type field tracks which model you are trying to relate to (Food or Wine in this case). The object_id field track which record in the Wine or Food table we are trying to track. content_object is a convenience attribute that allows us direct access to the object (once the review has been saved).

When creating a new review you just assign the Wine or Food to the content_object field:

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

这篇关于Django在两个人之间分享一个模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆