Django contenttypes 框架详解(小结)


Posted in Python onAugust 13, 2018

一、什么是Django ContentTypes?

Django ContentTypes是由Django框架提供的一个核心功能,它对当前项目中所有基于Django驱动的model提供了更高层次的抽象接口。 当然我们不是说的是http中的content-type!完全没有任何关系!

下面将一步一步解释Django ContentTypes在Django框架中做了什么,以及如何使用Django ContentTypes。 

当然,如果对于ContentTypes有了初步了解而只是不了解它的应用场景,可以直接查阅一下原文档:

https://docs.djangoproject.com/en/1.10/ref/contrib/contenttypes/

二、Django ContentTypes做了什么?

当使用django-admin初始化一个django项目的时候,可以看到在默认的INSTALL_APPS已经包含了django.contrib.contenttypes:

INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
]

而且注意django.contrib.contenttypes是在django.contrib.auth之后,这是因为auth中的permission系统是根据contenttypes来实现的。

我们来查询查阅了一下django.contrib.contenttypes.models文件:

class ContentType(models.Model):
  app_label = models.CharField(max_length=100)
  model = models.CharField(_('python model class name'), max_length=100)
  objects = ContentTypeManager()

  class Meta:
    verbose_name = _('content type')
    verbose_name_plural = _('content types')
    db_table = 'django_content_type'
    unique_together = (('app_label', 'model'),)

  def __str__(self):
    return self.name

大家可以看到ContentType就是一个简单的django model,而且它在数据库中的表的名字为django_content_type。

这个表的名字一般都不会陌生,在第一次对Django的model进行migrate之后,就可以发现在数据库中出现了一张默认生成的名为django_content_type的表。

如果没有建立任何的model,默认django_content_type是这样的:

Django contenttypes 框架详解(小结)

因此,django_content_type记录了当前的Django项目中所有model所属的app(即app_label属性)以及model的名字(即model属性)。

当然,django_content_type并不只是记录属性这么简单,contenttypes是对model的一次封装,

因此可以通过contenttypes动态的访问model类型,而不需要每次import具体的model类型。

  • ContentType实例提供的接口 
    • ContentType.model_class() 
      • 获取当前ContentType类型所代表的模型类
    • ContentType.get_object_for_this_type() 
      • 使用当前ContentType类型所代表的模型类做一次get查询
    • ContentType管理器(manager)提供的接口 
    • ContentType.objects.get_for_id() 
      • 通过id寻找ContentType类型,这个跟传统的get方法的区别就是它跟get_for_model共享一个缓存,因此更为推荐。
    • ContentType.objects.get_for_model() 
      • 通过model或者model的实例来寻找ContentType类型

三、Django ContentTypes的使用场景

在我们这个项目中各种商品的优惠卷就运用到了这个知识点:

假使我们models下有这几张表:

class Electrics(models.Model): #电器类
  name = models.CharField(max_length=32)
  price= models.IntegerField(default=100)

  def __str__(self):
    return self.name


class Foods(models.Model):   #食物类
  name = models.CharField(max_length=32)
  price = models.IntegerField(default=100)

  def __str__(self):
    return self.name


class Clothes(models.Model):  #衣服类
  name = models.CharField(max_length=32)
  price= models.IntegerField(default=100)
  def __str__(self):
    return self.name

class Coupon(models.Model):  #优惠券
  name = models.CharField(max_length=32)

  def __str__(self):
    return self.name

我们先来考虑一个问题,如何把这些商品和优惠卷相关联?

一种商品一个优惠卷,那我们就在表中加入一种商品的优惠券,就是一个一对多的ForeignKey,那么多个商品就有各种优惠卷,

但是一种商品的特定优惠卷在表结构中,就那个字段有值,别的不相关的记录为null,而且每增加一个商品,又要手动的去添加外键,

这是繁琐的!

所以我们就使用contenttypes 应用中提供的特殊字段GenericForeignKey,我们可以解决上面的问题:

只需要以下三步:

  • 在model中定义ForeignKey字段,并关联到ContentType表。通常这个字段命名为“content_type”
  • 在model中定义PositiveIntegerField字段,用来存储关联表中的主键。通常这个字段命名为“object_id”
  • 在model中定义GenericForeignKey字段,传入上述两个字段的名字。

具体实例代码:

class 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

这样的话不管表的数据都可以查询出来,而且添加新的商品的商品,也不需要动优惠券的源码。

但我们在查询的过程中,用ORM实在太繁琐了,所以还有一个反向查询的方法:

就是在每个商品中关联 绑定一个关系:

coupons = GenericRelation(to='Coupon') # 用于反向查询,不会生成表字段

这样我们就可以直接ORM的.coupons找相应的字段!

Python 相关文章推荐
python爬取51job中hr的邮箱
May 14 Python
《Python学习手册》学习总结
Jan 17 Python
深入浅析Python获取对象信息的函数type()、isinstance()、dir()
Sep 17 Python
从列表或字典创建Pandas的DataFrame对象的方法
Jul 06 Python
解决Python3 抓取微信账单信息问题
Jul 19 Python
python 的 scapy库,实现网卡收发包的例子
Jul 23 Python
python 多进程共享全局变量之Manager()详解
Aug 15 Python
Python socket非阻塞模块应用示例
Sep 12 Python
Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
Apr 20 Python
浅谈Pycharm的项目文件名是红色的原因及解决方式
Jun 01 Python
浅析Python requests 模块
Oct 09 Python
Python存储读取HDF5文件代码解析
Nov 25 Python
Python中的Numpy矩阵操作
Aug 12 #Python
浅谈python之新式类
Aug 12 #Python
详解Django中类视图使用装饰器的方式
Aug 12 #Python
python中pip的安装与使用教程
Aug 10 #Python
python3判断url链接是否为404的方法
Aug 10 #Python
Python实现数据可视化看如何监控你的爬虫状态【推荐】
Aug 10 #Python
Selenium元素的常用操作方法分析
Aug 10 #Python
You might like
PHP的mysqli_stmt_init()函数讲解
2019/01/24 PHP
ThinkPHP3.2.3框架实现的空模块、空控制器、空操作,跳转到错误404页面图文详解
2019/04/03 PHP
php ActiveMQ的安装与使用方法图文教程
2020/02/23 PHP
javascript动画浅析
2012/08/30 Javascript
鼠标移入移出事件改变图片的分辨率的两种方法
2013/12/17 Javascript
Nodejs使用mysql模块之获得更新和删除影响的行数的方法
2014/03/18 NodeJs
用JavaScript实现使用鼠标画线的示例代码
2014/08/19 Javascript
JavaScript定时显示广告代码分享
2015/03/02 Javascript
XML文件转化成NSData对象的方法
2015/08/12 Javascript
动态创建按钮的JavaScript代码
2016/01/29 Javascript
JavaScript学习总结之JS、AJAX应用
2016/01/29 Javascript
探究Vue.js 2.0新增的虚拟DOM
2016/10/20 Javascript
AngularJS中$http使用的简单介绍
2017/03/17 Javascript
自定义事件解决重复请求BUG的问题
2017/07/11 Javascript
深入理解React Native原生模块与JS模块通信的几种方式
2017/07/24 Javascript
js链表操作(实例讲解)
2017/08/29 Javascript
微信小程序下拉刷新界面的实现
2017/09/28 Javascript
基于vue.js 2.x的虚拟滚动条的示例代码
2018/01/23 Javascript
简单明了区分escape、encodeURI和encodeURIComponent
2018/05/26 Javascript
从零开始在NPM上发布一个Vue组件的方法步骤
2018/12/20 Javascript
js实现圆形显示鼠标单击位置
2020/02/11 Javascript
基于react项目打包css引用路径错误解决方案
2020/10/28 Javascript
Python用UUID库生成唯一ID的方法示例
2016/12/15 Python
python3中set(集合)的语法总结分享
2017/03/24 Python
python爬虫获取小区经纬度以及结构化地址
2018/12/30 Python
python加载自定义词典实例
2019/12/06 Python
python连接手机自动搜集蚂蚁森林能量的实现代码
2021/02/24 Python
HTML5实现经典坦克大战坦克乱走还能发出一个子弹
2013/09/02 HTML / CSS
手机配件第一品牌:ZAGG
2017/05/28 全球购物
Lampenwelt德国:欧洲领先的灯具和照明在线商店
2018/08/05 全球购物
Harrods英国:世界领先的奢侈品百货商店
2020/09/23 全球购物
献爱心活动总结
2014/05/07 职场文书
大学生简历求职信
2014/06/24 职场文书
2014年计划生育工作总结
2014/11/14 职场文书
python操作xlsx格式文件并读取
2021/06/02 Python
Python制作一个随机抽奖小工具的实现
2021/07/07 Python