@

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

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

我们对应着活动类型,对某类商品设计优惠卷,比如:

家电是一类商品、食物是一类商品,那么我们就可以设计家电折扣优惠券,以及食物满减优惠券等.

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

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]


最新文章

  1. React Native Android gradle下载慢问题解决
  2. Hash 函数及其重要性
  3. JAVA 多线程随笔 (二) sleep, yield, join, wait 和notify
  4. Lua.LearningLua.5-document-for-luaL_findtable-function
  5. Linux命令:ps / top
  6. mysql字段不能为空的字段为空时也能插入的方法
  7. ORACLE 变量定义
  8. ios数据库FMDB
  9. 397. Integer Replacement
  10. Android 连接 SQL Server (jtds方式)——下
  11. Linux磁盘分区(一):添加
  12. git 文件状态与工作区域
  13. python 之路,200行Python代码写了个打飞机游戏!
  14. Spring Security Oauth2 permitAll()方法小记
  15. typescript之初学习
  16. 剑指offer 14:链表中倒数第k个节点
  17. 力扣(LeetCode)258. 各位相加
  18. phalcon的save方法保存失败?
  19. Vue 爬坑之路(十)—— Vue2.5 + Typescript 构建项目
  20. 20165210 Java第六周学习总结

热门文章

  1. &lt;&lt;大学&gt;&gt;原文
  2. 2、go Defer
  3. [LNOI2014]LCA 树链剖分 离线 前缀和 思维题
  4. CSS display属性学习
  5. Hexo构建Blog系列
  6. Linux学习,部署django项目到服务器,及安装python,uwsgi等
  7. 【Codeforces Round #422 (Div. 2) B】Crossword solving
  8. Light OJ 1341 Aladdin and the Flying Carpet
  9. [BZOJ4026]dC Loves Number Theory 欧拉函数+线段树
  10. dotnet 命令的使用