博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django组件之contenttype
阅读量:4325 次
发布时间:2019-06-06

本文共 4277 字,大约阅读时间需要 14 分钟。

Django组件之contenttype

contenttype

  • contenttype是Django内置的一个应用,可以追踪项目中所有app和model的对应关系,并记录在ContentType表中
  • 每当我们创建了新的mode并执行了数据库迁移,ContentType表中就会新增一条记录。

实例场景

  • 先提供一个场景,网上商城购物时,会有各种各样的优惠券,比如通用优惠券,满减券,或者是仅限特定品类的优惠券。我们以往的方式是:在数据库中,可以通过外键将优惠券和不同品类的商品表关联起来:

    from django.db import modelsclass Electrics(models.Model):    """    id  name    1   日立冰箱    2   三星电视    3   小天鹅洗衣机    """    name = models.CharField(max_length=32)class Foods(models.Model):    """    id   name    1    面包    2    烤鸭    """    name = models.CharField(max_length=32)class Clothes(models.Model):    name = models.CharField(max_length=32)class Coupon(models.Model):    """    id     name            Electrics        Foods           Clothes        more...    1     通用优惠券       null              null            null               2     冰箱满减券         2               null            null    3     面包狂欢节        null              1              null    """    name = models.CharField(max_length=32)    electric_obj = models.ForeignKey(to='Electrics', null=True)    food_obj = models.ForeignKey(to='Foods', null=True)    cloth_obj = models.ForeignKey(to='Clothes', null=True)
  • 将所有的商品都关联到Coupon这张表中,如果是通用优惠券,那么所有的ForeignKey对应字段的值为null,如果仅限某些商品,那么对应商品ForeignKey记录该商品的id,不相关的记录为null

这样做存在的问题:

  1. 实际中商品品类繁多,而且很可能还会持续增加,那么优惠券表中的外键将越来越多,这样我们就要频繁的修改表
  2. 每条记录仅使用其中的一个或某几个外键字段,这样就会造成表空间的浪费。
  • 所以contenttype组件的作用就是为了解决这样的 问题

解决办法:

  • 通过使用contenttype 应用中提供的特殊字段GenericForeignKey,通过以下三个步骤来解决:

    1. 在model中定义Foreignkey字段,并关联到ContentType表,通常这个字段命名为content_type

    2. 在model中定义PositiveIntegerField字段,用来存储关联表中的主键,通常这个字段命名为-- object_id

    3. 在model中定义GenericForeignKey字段,传入上述俩个字段的名字

      -- 解决一张表要跟多张表建立外键关系的时候-- from django.contrib.contenttypes.model import ContentType   from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation    第一步  跟ContentType建立外键关系   content_type = models.ForeignKey(to=ContentType)   第二步  对象id   object_id = model.IntergerField()   第三步 表以及对象id绑定关系   content_obj = GenericForeignKey("content_type", "object_id")

      补充:为了方便反向查询,我们可以使用GenericRelation字段定义反向关系

实例代码

  • model.py定义表结构

    from django.db import modelsfrom django.contrib.contenttypes.models import ContentTypefrom django.contrib.contenttypes.fields import GenericForeignKeyclass Electrics(models.Model):    name = models.CharField(max_length=32)    coupons = GenericRelation(to='Coupon')  # 用于反向查询,不会生成表字段    def __str__(self):        return self.nameclass Foods(models.Model):    name = models.CharField(max_length=32)    coupons = GenericRelation(to='Coupon')    def __str__(self):        return self.nameclass Clothes(models.Model):    name = models.CharField(max_length=32)    coupons = GenericRelation(to='Coupon')    def __str__(self):        return self.nameclass Coupon(models.Model):    name = models.CharField(max_length=32)    content_type = models.ForeignKey(to=ContentType) # step 1    object_id = models.PositiveIntegerField() # step 2    content_object = GenericForeignKey('content_type', 'object_id') # step 3    def __str__(self):        return self.name
  • 创建记录和查询

    from django.shortcuts import render, HttpResponsefrom app01 import modelsfrom django.contrib.contenttypes.models import ContentTypedef test(request):    if request.method == 'GET':        # ContentType表对象有model_class() 方法,取到对应model        content = ContentType.objects.filter(app_label='app01', model='electrics').first()  # 表名小写        cloth_class = content.model_class() # cloth_class 就相当于models.Electrics        res = cloth_class.objects.all()        print(res)        # 为三星电视(id=2)创建一条优惠记录        s_tv = models.Electrics.objects.filter(id=2).first()        models.Coupon.objects.create(name='电视优惠券', content_object=s_tv)        # 查询优惠券(id=1)绑定了哪些商品        coupon_obj = models.Coupon.objects.filter(id=1).first()        prod = coupon_obj.content_object        print(prod)        # 查询三星电视(id=2)的所有优惠券        res = s_tv.coupons.all()        print(res)        # 查询obj的所有优惠券:如果没有定义反向查询字段,通过如下方式:        content = ContentType.objects.filter(app_label='app01', model='model_name').first()        res = models.OftenAskedQuestion.objects.filter(content_type=content, object_id=obj.pk).all()        return HttpResponse('....')
  • 总结:当一张表和多个表FK关联,并且多个FK中只能选择其中一个或其中n个时,可以利用contenttypes app,只需定义三个字段就搞定!常用的场景:一个商品的多种优惠券,一门课程按照周期的多种价格、一门课程各自的常见问题等等。

参考文档:

转载于:https://www.cnblogs.com/yuncong/p/10133005.html

你可能感兴趣的文章
Django 学习笔记(五) --- Ajax 传输数据
查看>>
Spring boot 日志 Logback
查看>>
基于OWIN WebAPI 使用OAUTH2授权服务【授权码模式(Authorization Code)】
查看>>
[深入Maven源代码]maven绑定命令行参数到具体插件
查看>>
laravel 分页使用
查看>>
RobotFramework自动化2-自定义关键字
查看>>
centos6.4-x86-64系统更新系统自带Apache Http Server
查看>>
[置顶] 【cocos2d-x入门实战】微信飞机大战之三:飞机要起飞了
查看>>
BABOK - 需求分析(Requirements Analysis)概述
查看>>
第43条:掌握GCD及操作队列的使用时机
查看>>
Windows autoKeras的下载与安装连接
查看>>
CMU Bomblab 答案
查看>>
微信支付之异步通知签名错误
查看>>
2016 - 1 -17 GCD学习总结
查看>>
linux安装php-redis扩展(转)
查看>>
Vue集成微信开发趟坑:公众号以及JSSDK相关
查看>>
vue项目开发之v-for列表渲染的坑
查看>>
C# 输出流转化成输入流操作XML
查看>>
CSS外边距合并(塌陷/margin越界)
查看>>
Swift给每个开发者赢取500万的机会!不看一生后悔。
查看>>