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

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

id app_label model
admin, auth等内置应用…
5 contenttypes contenttype
6 app01

electrics

  那么这个表有什么作用呢?

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

from django.db import models

class 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.每条记录仅使用其中的一个或某几个外键字段,这样就会造成表空间的浪费。

解决方法:

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

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

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

示例代码:

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey class Electrics(models.Model):
name = models.CharField(max_length=32)
coupons = GenericRelation(to='Coupon') # 用于反向查询,不会生成表字段 def __str__(self):
return self.name class Foods(models.Model):
name = models.CharField(max_length=32)
coupons = GenericRelation(to='Coupon') def __str__(self):
return self.name class Clothes(models.Model):
name = models.CharField(max_length=32)
coupons = GenericRelation(to='Coupon') def __str__(self):
return self.name 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

创建记录和查询

from django.shortcuts import render, HttpResponse
from app01 import models
from django.contrib.contenttypes.models import ContentType def 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,只需定义三个字段就搞定!常用的场景:一个商品的多种优惠券,一门课程按照周期的多种价格、一门课程各自的常见问题等等。

Django组件之contenttype的应用的更多相关文章

  1. Django 组件之 ----- content-type

    Django 组件之 content-type的使用 一个表和多个表进行关联,但具体随着业务的加深,表不断的增加,关联的数量不断的增加,怎么通过一开始通过表的设计后,不在后期在修改表,彻底的解决这个问 ...

  2. 19,django组件之contenttype(一)

    django组件之contenttype(一) 方式1:适用于1张表和另一张表要关联的时候. 1.路飞学成表设计: 2.将2个价格策略表合并1张表. 3.如果再加一张表,那价格策略表的表结构会发生改变 ...

  3. 05 django组件:contenttype

    1.django组件:contenttype 组件的作用:可以通过两个字段让表和N张表创建FK关系 1.专题课,学位课 如何关联 过期时间?? 方法1:分别创建 专题课--过期时间表 .学位课--过期 ...

  4. django组件之ContentType

    ContentTyep组件: 帮助我们关联所有数据库的表 帮助我们反向查询关联数据表中的所有策略信息 GenericForeignkey(帮助我们快速插入数据) GenericRelation(用于反 ...

  5. django组件之contenttype(一)

    方式1:适用于1张表和另一张表要关联的时候. 1.路飞学成表设计: 2.将2个价格策略表合并1张表. 3.如果再加一张表,那价格策略表的表结构会发生改变.  这样不合理的,我们的表结构一般设计完就不会 ...

  6. python 全栈开发,Day76(Django组件-cookie,session)

    昨日内容回顾 1 json 轻量级的数据交换格式 在python 序列化方法:json.dumps() 反序列化方法:json.loads() 在JS中: 序列化方法:JSON.stringfy() ...

  7. Django - 文件上传、Django组件 - 分页器(paginator)

    一.文件上传准备知识 - Content-Type 1.请求头 - Content-Type Content-Type指的是请求体的编码类型,常见的类型共有3种: 1)application/x-ww ...

  8. Django组件-cookie,session

    昨日内容回顾: json 轻量级的数据交换格式 在python 序列化方法:json.dumps() 反序列化方法:json.loads() 在JS中: 序列化方法:JSON.stringfy() 反 ...

  9. python 全栈开发,Day78(Django组件-forms组件)

    一.Django组件-forms组件 forms组件 django中的Form组件有以下几个功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显 ...

随机推荐

  1. IDEA使用maven构建时控制台中文乱码的解决办法

    使用maven clean install 项目时控制台中文乱码,解决办法如下: Setting->maven->runner VMoptions: -Dfile.encoding=UTF ...

  2. MySql动态生成SQL并执行

    场景:由于一些表中设计了一些冗余字段,因此在主表修改了该冗余字段的值得时候,需要动态更新在其他表中冗余字段的值 BEGIN #Routine body goes here... /*SQL语句变量*/ ...

  3. 【转】cocos2dx 3.x 集成protobuf

    http://www.cnblogs.com/chevin/p/6001872.html vs2013+cocos2dx 3.13.1 这篇博文是集成Lua版本的protobuf,集成C++版本的过程 ...

  4. DataGridView加载gif图片

    当我们想加载图片时,一般情况下都会使用picturebox控件,这个控件可以加载各种格式的图片,当然也包括gif图片.但是有时,我们也希望一些数据展示控件也可以加载图片,比如说DataGridView ...

  5. can be found for element 'tx:annotation-driven'

    错误描述: ERROR [ContainerBackgroundProcessor[StandardEngine[Catalina]]] (ContextLoader.java:308) - Cont ...

  6. 使用JSON数据格式模拟股票实时信息

    JQueryStock.html <!DOCTYPE html> <head> <meta charset="UTF-8"> <title ...

  7. PHP的报错级别并返回当前级别error_reporting()

    定义和用法:error_reporting() 设置 PHP 的报错级别并返回当前级别.函数语法:error_reporting(report_level) 如果参数 level 未指定,当前报错级别 ...

  8. mysql的增量备份

    1,在mysql 的my.ini文件中 2在我的D盘下创建binlog文件夹 3重启mysql服务可以看到我的D盘下的binlog下生成如下文件 4,在默认的test数据库中创建t_one1这张表 c ...

  9. Visio中的Undo和Redo

    1.Visio默认Undo和Redo操作是可用的,Appliacation中的UndoEnabled标志Undo和Redo操作是否可用. m_Visio.Window.Application.Undo ...

  10. [Leetcode] subsets ii 求数组所有的子集

    Given a collection of integers that might contain duplicates, S, return all possible subsets. Note: ...