Django中content-type组件

django-content

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")
models.py

自定义插入数据

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)
views.py

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')
models.py
# 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)
views.py

通过粤菜中的冰镇花蟹找到对应的价格

# 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')
models.py
# 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("查询成功")
views.py

总结:content-type组件适用于,多张表外键关系关联到同一张表的场景,且并不能选择那张表的所有数据,即:价格表中的所有数据并不是都关联粤菜表,只有一部分关联。GenericForeignKey用于正向关联用,GenericRelation用于反向关联用。

 

posted @ 2019-10-30 11:45  Lowell  阅读(175)  评论(0编辑  收藏  举报