当一张表和多个表ForeignKey关联,并且多个FK中只能选择其中一个或其中n个时,可以利用contenttypes,只需定义三个字段就搞定!

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

每当我们创建了新的model并执行数据库迁移后,ContentType表中就会自动新增一条记录。比如我在应用app的models.py中创建表class Electrics(models.Model): pass。从数据库查看ContentType表,显示如下:

那么这个表有什么作用呢?这里提供一个场景,网上商城购物时,会有各种各样的优惠券,比如通用优惠券,满减券,或者是仅限特定品类的优惠券。在数据库中,可以通过外键将优惠券和不同品类的商品表关联起来:

from django.db import modelsclass Electrics(models.Model):"""id  name1   日立冰箱2   三星电视3   小天鹅洗衣机"""name = models.CharField(max_length=32)class Foods(models.Model):"""id   name1    面包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            null3     面包狂欢节        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)

常规写法

如果是通用优惠券,那么所有的ForeignKey为null,如果仅限某些商品,那么对应商品ForeignKey记录该商品的id,不相关的记录为null。但是这样做是有问题的:实际中商品品类繁多,而且很可能还会持续增加,那么优惠券表中的外键将越来越多,但是每条记录仅使用其中的一个或某几个外键字段。

通过使用contenttypes 应用中提供的特殊字段GenericForeignKey,我们可以很好的解决这个问题。只需要以下三步:

  • 在model中定义ForeignKey字段,并关联到ContentType表。必须这个字段命名为“content_type”
  • 在model中定义PositiveIntegerField字段,用来存储关联表中的主键。必须这个字段命名为“object_id”,否则GenericRelation反向查找的时候会报错
  • 在model中定义GenericForeignKey字段,传入上述两个字段的名字。

为了更方便查询商品的优惠券,我们还可以在商品类中通过GenericRelation字段定义反向关系。

from django.db import models
from django.contrib.contenttypes.models import ContentType
from 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 添加一个字段,关联ContentType表中的某一个表object_id = models.PositiveIntegerField() # step 2 添加一个id字段,就是‘某一张’表在ContentType里的对应的idcontent_object = GenericForeignKey('content_type', 'object_id') # step 3 不会添加字段,只是为了插入或者查询时使用def __str__(self):return self.name

contenttype写法

from django.shortcuts import render, HttpResponse
from app01 import models
from django.contrib.contenttypes.models import ContentTypedef test(request):if request.method == 'GET':# ContentType表对象有model_class() 方法,取到对应modelcontent = ContentType.objects.filter(app_label='app01', model='electrics').first()  # 表名小写cloth_class = content.model_class() # cloth_class 就相当于models.Electricsres = 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)  #直接用content_object属性添加,无需给contenttype和object_id字段分别赋值
<br>    # 查询优惠券(id=1)绑定了哪些商品coupon_obj = models.Coupon.objects.filter(id=1).first()prod = coupon_obj.content_objectprint(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() <br>    <br><br>    return HttpResponse('....')

记录和查询

------------------------------------------------------------------------------------------------------------------------------------------------

PS:在model中定义PositiveIntegerField字段,必须用“object_id”,否则GenericRelation反向查找的时候会报错!!!

转载于:https://www.cnblogs.com/wrxblog/p/10556381.html

「Django」contenttypes基本用法相关推荐

  1. 「Django」rest_framework学习系列-用户认证

    用户认证: 1.项目下utils文件写auth.py文件 from rest_framework import exceptions from api import models from rest_ ...

  2. word怎么设置边距为80磅_Word排版不能忽视的「标尺」工具,6 种用法 80% 的人不知道!...

    Word中的标尺工具,你有关注过吗?你会用吗? 标尺,作用如其名,就像生活中使用的直尺那样,可以用来精确地测量和控制文档中内容的位置.它看似是平淡无奇,容易被我们忽略.其实,利用它可以帮我们快速完成很 ...

  3. 新年「开门红」| 送你 108 份开工牛气能量!

    人勤春来早 牛年向前 "犇"!  正月初七,迎来新年第一个工作日 祝大家开工大吉! 小楼为你送上 108 门免费项目课程,愿你新年第一天,元气加满,更上一层楼! 具体课程如下,如果 ...

  4. 如何直观地理解「协方差矩阵」?

    如何直观地理解「协方差矩阵」? Xinyu Chen Urban Traffic Data Analytics 372 人赞同了该文章 协方差矩阵在统计学和机器学习中随处可见,一般而言,可视作方差和协 ...

  5. 有人统计了2万篇论文发现:想增加引用量,最好少说「黑话」

    本文经机器之心(微信公众号:almosthuman2014)授权转载,禁止二次转载 编辑:蛋酱 BERT.GAN.LSTM 都是些什么东西?对自己没有点信心,最好不要制造这么多新单词. 如果你想让自己 ...

  6. 80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩!

    80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩! 2018年05月02日 00:00:00 阅读数:366 作者 | 蔡一  志顶科技技术总监 4月6日,Daniel Larime ...

  7. 不挂载 组件渲染_让你的 React 组件性能跑得再快一点「实践」

    作者:天泽 转发链接:https://www.zoo.team/article/react-render 性能和渲染(Render)正相关 React 基于虚拟 DOM 和高效 Diff 算法的完美配 ...

  8. devc++源文件未编译_悬赏万元,重现「木兰」编程语言编译器

    下面内容不一定及时更新.最近更新见github源repo: 重金悬赏,重现「木兰」编程语言编译器​github.com 本人特此声明: 任何人,可以借助于任何现有开源技术,包括 Python 编译器本 ...

  9. 用typescript完成倒计时_「干货」将数十万行CoffeeScript代码迁移到TypeScript

    作者 | David Goldstein 译者 | 王强 策划 | 小智 转发链接:https://mp.weixin.qq.com/s/TK7kWXX4hR3e-jtpVMuBnw 序言 2017 ...

  10. 当一个美术生开始在腾讯撸代码… |「递归」第1集

    我们为什么叫「递归」 "递归" (recursion) 是一种在程序设计语言中被广泛使用的算法.它有两大特点,一是调用自己,二是化繁为简.我们当中那些优秀的技术人又何尝不是如此?他 ...

最新文章

  1. Redis介绍使用及进阶
  2. 一起谈.NET技术,Visual Studio 2010 中的代码约定设置
  3. hdu 1298 字典树 + DFS (模拟T9文本输入)
  4. LevelDB 源码剖析(一)准备工作:环境搭建、接口使用、常用优化
  5. ASPNET Core 2.x中的Kestrel服务器
  6. scala 函数调用_在Scala中按名称调用函数
  7. mysql host %s_python mysql:虽然%s和列匹配,但并非SQL语句中使用的所有参数
  8. pytorch1.7教程实验——DCGAN生成对抗网络
  9. leetcode —— 1079. 活字印刷
  10. 安装floodlight遇到的问题和解决
  11. python基础之模块初识
  12. 对数几率回归(Logistic Regression)
  13. GIT在WINDOWS/LINUX下载的源码,回车换行有差异
  14. Java、JSP网上花店系统
  15. Win10相机打不开提示:我们找不到你的相机 错误代码0xa00f4244!
  16. 服务器部署方案文档,IBM目录服务器部署方案
  17. 怎么修改teredo服务器,技术员设置win7系统通过teredo连接IPv6的修复方案
  18. HGDB 兼容 Oracle 中 merge into using(APP)
  19. 服务器主板用什么芯片,C610芯片服务器主板用什么机箱好?
  20. 笔试强训48天——day29

热门文章

  1. android apk 可以直接放在systemapp下吗,内置语音apk到/system/app下的问题
  2. c语言程序设计教程期末考试,《C语言程序设计》课程考核方案
  3. 【git】常用命令行收集
  4. bootstrap中关于兼容ie8 和 rem的问题总结
  5. Url...................哈哈哈哈哈哈哈哈哈
  6. [Poi2000]公共串 hustoj2797
  7. cocos2d学习之路四(添加遥控杆)
  8. D3.js学习(二)
  9. 回溯____蓝桥 棋盘
  10. 中国新一代海洋综合科考船“科学”号返回母港