• Django ContentType组件


     

    需求

    现在我们有这样一个需求~我们的商城里有很多的商品~~节日要来了~我们要搞活动~~

    那么我们就要设计优惠券~~优惠券都有什么类型呢~~满减的~折扣的~立减的~~

    我们对应着我们活动类型~对我们的某类商品设计优惠券~~比如~~

    家电是一类商品~~食物是一类商品~那么我们可以设计家电折扣优惠券~~以及食物满减优惠券等~

    那么我们看表结构怎么设计~~

    第一版本

    from django.db import models
    
    
    # 设计表结构      # 第一版设计
    class Food(models.Model):
        name = models.CharField(max_length=32)
    
    
    class Fruit(models.Model):
        name = models.CharField(max_length=32)
    
    
    class Coupon(models.Model):
        title = models.CharField(max_length=32)
        food = models.ForeignKey(to="Food")
        fruit = models.ForeignKey(to="Fruit")
    第一版 直接来个外键!

     但是 发现商品太多  name外键也要加很多   name表结构就很不合理

    第二版本 

    from django.db import models
    
    
    class Food(models.Model):
        """食物表"""
        name = models.CharField(max_length=32)
    
    
    class Fruit(models.Model):
        """水果表"""
        name = models.CharField(max_length=32)
    
    
    class Coupon(models.Model):
        """优惠券表
        这时候 设计字段为  表的id   和  object的对象id
            表的id  就是找到对应的表
            object的id  就可以找到表里边对应的对象
    
        就是定位的方法
        """
        title = models.CharField(max_length=32)
        table = models.ForeignKey(to=MyTables)
        object_id = models.IntegerField()
    
    class MyTables(models.Model):
        """
        id     app_name    table_name
        1       Demo        Food   # 对应的外键是 1
        2       Demo        Fruit  # 对应的外键是 2
        """
        app_name = models.CharField(max_length=32)
        table_name = models.CharField(max_length=32)
    第二版

    就是通过外键到第三张表MyTables找到对应的app中(水果,食物、、)等类的表,  然后通过根据表中对象对应的id拿到具体的对象这样方法可行吗?

    其实django已经帮我们设计好了

    遇到这种一张表要跟多张表进行外键关联的时候~我们Django提供了ContentType组件~

    ContentType组件

    注释所有的model文件执行数据库迁移

    pythno manage.py migrate

    ContentType是Django的内置的一个应用,可以追踪项目中所有的APP和model的对应关系,并记录在ContentType表中。

    当我们的项目做数据迁移后,会有很多django自带的表,其中就有django_content_type表,我们可以去看下~~~

     

    ContentType组件应用:

      -- 在model中定义ForeignKey字段,并关联到ContentType表,通常这个字段命名为content-type

      -- 在model中定义PositiveIntergerField字段, 用来存储关联表中的主键,通常我们用object_id

      -- 在model中定义GenericForeignKey字段,传入上面两个字段的名字

      --  方便反向查询可以定义GenericRelation字段

    代码如下:

      

     

    数据迁移后~添加数据~我们看下增删改查的操作~~

    基本的使用~

    # 第三版
    from django.db import models
    from django.contrib.contenttypes.models import ContentType  # 定位django表使用
    from django.contrib.contenttypes.fields import GenericForeignKey  # 定位表中字段对应对象使用
    from django.contrib.contenttypes.fields import GenericRelation  # 反向查询使用
    
    
    # 设计表结构      # 第三版设计
    class Food(models.Model):
        """食物表"""
        name = models.CharField(max_length=32)
        coupons = GenericRelation(to="Coupon")  # 不生成字段 只用于方向查询
    
    
    class Fruit(models.Model):
        """水果表"""
        name = models.CharField(max_length=32)
        coupons = GenericRelation(to="Coupon")  # 不生成字段 只用于方向查询
    
    
    class Coupon(models.Model):
        """优惠券表"""
        title = models.CharField(max_length=32)
        # 第三版 使用Django自带的ContentType表
    
        # 外键到Django自带的ContentType表
        content_type = models.ForeignKey(to=ContentType)  # 相当于 找到可以定位到表
        object_id = models.IntegerField()  # 相当于 定位在表的对应的对象id
    
        # 不会生成字段 用于关联到对象的(建立关系)
        content_object = GenericForeignKey("content_type", "object_id")
    django 自带ContentType

    简单测试

    添加食物数据

    添加水果数据

     添加测试url

    from django.conf.urls import url
    
    from .views import TestView
    
    urlpatterns = [
    
        url(r'^test', TestView.as_view()),
    ]
    urls
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import Food, Fruit, Coupon
    from django.contrib.contenttypes.models import ContentType
    
    
    class TestView(APIView):
    
        def get(self, request):
            # 找到表id以及表对象
            # content_type_obj = ContentType.objects.filter(app_label="ContentType", model="food").first()
            #
            # print(type(content_type_obj), "**", content_type_obj)  # 拿到表中表名
            # # <class 'django.contrib.contenttypes.models.ContentType'> ** food
            #
            # model_class = content_type_obj.model_class()  # 拿到模型表对象
            # print(model_class)  # <class 'ContentType.models.Food'>
            # # <class 'ContentType.models.Food'>
            # print(content_type_obj.pk)  # 获得表中对应id   # (pk和id是一样的)
    
            # # 给酱香饼创建优惠券
            # food_obj = Food.objects.filter(id=1).first()  # 库中的id为1
            # Coupon.objects.create(title="酱香饼半价啦", content_object=food_obj)  # 在视图中content_object做了关系
            #
            # # 给黑美人西瓜加优惠券
            # fruit_obj = Fruit.objects.get(id=2)  # 库中的id为2
            # Coupon.objects.create(title="黑美人2折", content_type_id=9, object_id=2)  # 使用原生方法创建优惠券
    
            # 查询优惠券绑定对象(看看id为1的优惠券是对应那个商品)
            coupon_obj = Coupon.objects.filter(id=1).first()
            print(coupon_obj.content_object.name)  # 酱香饼  # content_object建立了关系
    
            # 查某个对象的优惠券
            food_obj = Food.objects.filter(id=1).first()
            print(food_obj.coupons.all())  # 拿到queryset集合对象  <QuerySet [<Coupon: Coupon object>]>
            
            return Response("ok")
    简单测试方便理解
  • 相关阅读:
    weekly review 200908: Talk Show of ASP.NET
    weeklyreview 200911: Drowse of Spring
    数据库中标识种子(否,是,是(不用于复制))解释
    Hashtable.ContainsKey跟Hashtable.Contains的区别
    【Oracle学习起步1】用户解锁及密码输入问题
    C#弹出对话框实现
    因为文件组 'PRIMARY' 已满。
    SQL删除数据的各种方式总结
    C standard library contents
    scanf("%c",&c)前的printf函数调用问题
  • 原文地址:https://www.cnblogs.com/clbao/p/9991168.html
Copyright © 2020-2023  润新知