• 【Django】ContentType组件


    @


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

    那么,我们就要设计优惠券,优惠券都有什么类型呢?满减的、折扣的、立减的、等等等...

    我们对应着活动类型,对某类商品设计优惠卷,比如:
    家电是一类商品、食物是一类商品,那么我们就可以设计家电折扣优惠券,以及食物满减优惠券等.

    所以,我们一顺手,表结构就出来了:

    from django.db import models
    
    is_true = {'null': True, 'blank': True}
    
    
    # 家用电器表
    class Appliance(models.Model):
        """
        id  name
        1   冰箱
        2   电视
        3   洗衣机
        """
        name = models.CharField(max_length=64)
    
    
    # 食品表
    class Food(models.Model):
        """
        id  name
        1   面包
        2   牛掰
        """
        name = models.CharField(max_length=64)
    
    
    # 水果表
    class Fruit(models.Model):
        """
        id  name
        1   苹果
        2   香蕉
        """
        name = models.CharField(max_length=64)
    
    
    # class ...
    
    
    # 优惠卷表
    class Coupon(models.Model):
        """
        id    title    appliance_id    food_id    fruit_id
        1   通用优惠卷     null          null        null
        2   冰箱折扣券       1           null        null
        3   电视折扣券       2           null        null
        4   苹果满减卷     null          null         1
        """
        title = models.CharField(max_length=64)
        appliance = models.ForeignKey(to='Appliance', **is_true)
        food = models.ForeignKey(to='Food', **is_true)
        fruit = models.ForeignKey(to='Fruit', **is_true)
        # ...
        # 实际上我们的商品种类会特别多,导致我们这张表的外键也越来越多
    

    殊不知,我们的大Django早就为我们提供了更高明的用法——ContentType组件.


    理解

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

    当我们的项目做数据迁移后,会在数据库中生成一些Django自带的表,其中就包含django_content_type表.

    我们先来看看这张表:
    在这里插入图片描述
    再来看看这张表内默认的数据:
    在这里插入图片描述
    可见,自动就建立了所有APP与其数据表的对应关系.


    表结构

    步骤

    1. 在model中定义ForeignKey字段,并关联到ContentType表,通常这个字段命名为content-type.
    2. 在model中定义PositiveIntergerField字段,用来存储步骤一中被外键的表中的主键,通常这个字段命名为object_id.
    3. 在model中定义GenericForeignKey字段,传入上面两个字段的名字.
    4. 为了方便反向查询,可在被外键表中定义GenericRelation字段并指向创建外键的表.

    好,根据开篇的表结构示例以及如上的步骤,我们的新表结构又出来了:

    from django.db import models
    from django.contrib.contenttypes.models import ContentType
    from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    
    
    # 家用电器表
    class Appliance(models.Model):
        name = models.CharField(max_length=64)
        # 4. 为了方便反向查询,可在被外键表中定义GenericRelation字段并指向创建外键的表
        coupons = GenericRelation(to='Coupon')
    
    # 食物表
    class Food(models.Model):
        name = models.CharField(max_length=64)
    
    
    # 水果表
    class Fruit(models.Model):
        name = models.CharField(max_length=64)
    
    
    # 优惠卷表
    class Coupon(models.Model):
        title = models.CharField(max_length=64)
        # 1. 在model中定义ForeignKey字段,并关联到ContentType表
        content_type = models.ForeignKey(to=ContentType)  # 这里就不要加引号了
        # 2. 在model中定义PositiveIntergerField字段,用来存储步骤一中被外键的表中的主键
        object_id = models.PositiveIntegerField()
        # 3. 在model中定义GenericForeignKey字段,传入上面两个字段的名字.
        content_object = GenericForeignKey('content_type', 'object_id')
    

    数据迁移后,django_content_type表中自动就增加了APP与其model的对应字段.

    使用

    首先 我们准备些数据

    # 在Python脚本中调用Django环境
    import os
    
    if __name__ == '__main__':
        # 注意将下面的'blog097.settings'改为对应的配置文件路径
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blog097.settings')
        import django
        django.setup()
        from blog import models
    
        [models.Appliance.objects.create(name=i) for i in ("冰箱", "电视", "洗衣机")]
        [models.Food.objects.create(name=i) for i in ("面包", "牛奶")]
        [models.Fruit.objects.create(name=i) for i in ("苹果", "香蕉")]
    

    如果不能理解此操作,可见博文:【在Python脚本中调用Django环境】

    然后 开始我们的ORM操作

    # 在Python脚本中调用Django环境
    import os
    
    if __name__ == '__main__':
        # 注意将下面的'blog097.settings'改为对应的配置文件路径
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blog097.settings')
        import django
        django.setup()
        from blog import models
        from django.contrib.contenttypes.models import ContentType
    
        """通过ContentType获得表名"""
        content_type_obj = ContentType.objects.filter(app_label='blog', model='appliance').first()  # 打印结果:appliance
    
        """获得表内的所有对象,相当于models.Applicance"""
        model_class = content_type_obj.model_class()  # <class 'blog.models.Appliance'>
        obj_list = model_class.objects.all()
        [print(obj.name) for obj in obj_list]  # 冰箱、电视、洗衣机
    
        """为冰箱添加一条优惠记录"""
        ice_box = models.Appliance.objects.filter(name="冰箱").first()
        models.Coupon.objects.create(title="冰箱折扣券", content_object=ice_box)
    
        """查询冰箱的所有优惠卷"""
        # 我们定义了反向查询
        coupon_list01 = ice_box.coupons.all()
        [print(coupon.title) for coupon in coupon_list01]
    
        # 如果没有定义反向查询
        coupon_list02 = models.Coupon.objects.filter(content_type=content_type_obj, object_id=ice_box.id).all()
        [print(coupon.title) for coupon in coupon_list02]
    


  • 相关阅读:
    TreeSelect组件:vmodel语法糖进行父子组件传值案例
    带 icon 的输入框:slot方式。slot="prefix"和slot="suffix"
    双向绑定vmodel与单向绑定vbind:value
    使用Set集合对List集合去重
    前端报错: error in ./src/assets/fonts/iconfont.svg?t=1523541245904,Module parse failed: Unexpected token (1:0),vue.config.js中引入chainWebpack后报错
    当主键不是id时,而是其他字段,那么该字段要加上@Id注解(除了表中指定主键,实体类中也要用@Id指定主键)
    java将文件转为base64字符串和将base64字符串转为文件
    父组件向子组件传递getList方法:provide/inject
    带卡片的input输入框
    C#中使用#if DEBUG
  • 原文地址:https://www.cnblogs.com/zyk01/p/10176356.html
Copyright © 2020-2023  润新知