1.需求
-
一家餐馆,有多个菜系,粤菜、湘菜、闽南菜、东北菜等,每个菜系中的菜品又分为小份、中份、大份,每个菜系对应的菜品量价格不同,现需要将该需求建表。
2. 建表方式
方案一:每个菜系一张表,每个菜系的价格对应一张表,每增加一个菜系都会增加一张表
方案二:方案一的基础上简单升级版,每个菜单表和第三张表关联,此时每增加一个菜系,价格表需要增加一个字段
方案三:方案二的基础上升级,添加菜系字段,这样不需要变更表结构,也不需要新增表
当我们简单创建两张表时候可以发现,django中有一个django_content_type表,里面存了app和对应表的关系。
方案四:通过django_content_type表修改
models.py
from django.db import models from django.contrib.contenttypes.models import ContentType class YueCai(models.Model): """粤菜""" dish_name = models.CharField(max_length=32) class XiangCai(models.Model): """湘菜""" dish_name = models.CharField(max_length=32) class Price(models.Model): """价格表""" fenliang = ( (1, "大份"), (2, "中份"), (3, "小份"), ) weight = models.IntegerField(choices=fenliang) price = models.DecimalField(8,2) content_type = models.ForeignKey(ContentType,verbose_name="关联菜系名",on_delete=models.CASCADE) dish_id = models.IntegerField(verbose_name="关联各个菜系中菜品id")
自定义插入数据
from app02 import models def test(request): # 为粤菜中冰镇花蟹的大份添加价格为299的数据 yobj = models.YueCai.objects.filter(dish_name="冰镇花蟹").first() cobj = models.ContentType.objects.filter(model="yuecai").first() # 我们自己去写需要写每个字段 models.Price.objects.create(weight=1,price=299,dish_id=yobj.id,content_type_id=cobj.id) obj_set = models.Price.objects.all().values() return HttpResponse(obj_set)
3.content-type组件的使用
为粤菜中冰镇花蟹的大份添加价格为299的数据
# models.py from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey class YueCai(models.Model): """粤菜""" dish_name = models.CharField(max_length=32) class XiangCai(models.Model): """湘菜""" dish_name = models.CharField(max_length=32) class Price(models.Model): """价格表""" fenliang = ( (1, "大份"), (2, "中份"), (3, "小份"), ) weight = models.IntegerField(choices=fenliang) price = models.DecimalField(8,2) content_type = models.ForeignKey(ContentType,verbose_name="关联菜系名",on_delete=models.CASCADE) dish_id = models.IntegerField(verbose_name="关联各个菜系中菜品id") # 不会改变表结构,只是为了帮助我们快速实现content-type操作 content_obj = GenericForeignKey('content_type','dish_id')
# views.py from django.shortcuts import render,HttpResponse from app02 import models def test(request): # 为粤菜中冰镇花蟹的大份添加价格为299的数据 # 我们只需要直接插入冰镇花蟹这个数据对象,给到content_obj,会通过yobj对象自动去content_type表中找到YueCai对应的id,和yobj对象id插入数据库中 yobj = models.YueCai.objects.filter(dish_name="冰镇花蟹").first() models.Price.objects.create(weight=1,price=299,content_obj=yobj) obj_set = models.Price.objects.all().values() return HttpResponse(obj_set)
通过粤菜中的冰镇花蟹找到对应的价格
# models.py from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.db import models from django.contrib.contenttypes.models import ContentType class YueCai(models.Model): """粤菜""" dish_name = models.CharField(max_length=32) coupons = GenericRelation(to="Price") # 定义反向查询字段,数据库中不会添加新的列 class XiangCai(models.Model): """湘菜""" dish_name = models.CharField(max_length=32) coupons = GenericRelation(to="Price") # 定义反向查询字段,数据库中不会添加新的列 class Price(models.Model): """价格表""" fenliang = ( (1, "大份"), (2, "中份"), (3, "小份"), ) weight = models.IntegerField(choices=fenliang) price = models.IntegerField() content_type = models.ForeignKey(ContentType,verbose_name="关联菜系名",on_delete=models.CASCADE) object_id = models.IntegerField(verbose_name="关联各个菜系中菜品id") # 不会改变表结构,只是为了帮助我们快速实现content-type操作 content_obj = GenericForeignKey('content_type','object_id')
# views.py from django.shortcuts import render,HttpResponse from app02 import models def test(request): # 通过粤菜中的冰镇花蟹找到对应的价格 obj_list = models.YueCai.objects.filter(dish_name="冰镇花蟹") for obj in obj_list: # obj.coupons.all()获取到关联的Price的价格对象列表 print(obj.coupons.all()) # <QuerySet [<Price: Price object (13)>]> for price_obj in obj.coupons.all(): print(f"份量:{price_obj.get_weight_display()}") print(f"价格:{price_obj.price}") print(f"菜系:{price_obj.content_type}") print(f"菜名:{price_obj.content_obj.dish_name}") return HttpResponse("查询成功")
总结:content-type组件适用于,多张表外键关系关联到同一张表的场景,且并不能选择那张表的所有数据,即:价格表中的所有数据并不是都关联粤菜表,只有一部分关联。GenericForeignKey用于正向关联用,GenericRelation用于反向关联用。