python框架之Django(15)-contenttype模块
假如有一个书城系统,需要给作者和书籍加上评论功能。如果给每个表单独建一个评论表,那么我们以后要扩展其它模块评论功能的时候,还需要随之新建一张评论表,会显得很冗余。对于这种情况,Django 给我们提供了解决方案,那就是 contenttypes 模块。
模型
from django.db import models
from django.contrib.contenttypes.models import ContentType class Book(models.Model):
'''
书籍表
'''
title = models.CharField(max_length=32) # 书籍标题 class Author(models.Model):
name = models.CharField(max_length=32) # 作者名称 class Comment(models.Model):
'''
评论表
'''
content_type = models.ForeignKey(ContentType, on_delete=None) # 被评论表(对哪张表进行评论)
object_id = models.PositiveIntegerField() # 被评论表中数据的id
content = models.CharField(max_length=200) # 评论内容
上述的表结构很简单,但是注意 Comment 表中的 content_type 字段,它关联的是 django.contrib.contenttypes.models.ContentType 这张表,而这张表就是 Django 为我们提供的,初始化 DB 时就会自动生成。看一下它的数据:
可以看到,它其实就是一张描述我们所建的模型和 Django 内置模型的信息表。而我们通过 Comment 表中的 content_type 字段与之关联,就可以标识出某条评论属于哪个模型(在这里描述的就是某条评论,是对作者,还是对书籍)。再通过 object_id 字段,关联到模型的主键,就可以标识出某条评论属于哪个模型的哪条数据(在这里描述的就是某条评论,是对某个作者,还是对某本书籍)。
新增数据
初始化测试数据:
import os if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
import django django.setup() from api import models
from django.contrib.contenttypes.models import ContentType models.Author.objects.create(name='鲁迅')
models.Author.objects.create(name='郭德纲')
models.Book.objects.create(title='傻子是这样炼成的')
models.Book.objects.create(title='永夜')
models.Book.objects.create(title='武则天传奇') models.Comment.objects.create(object_id=1, content_type=ContentType.objects.get(id=7), content='鲁大哥,666666') # 鲁迅
models.Comment.objects.create(object_id=1, content_type=ContentType.objects.get(id=7), content='鲁大哥 我占了二楼') # 鲁迅
models.Comment.objects.create(object_id=2, content_type=ContentType.objects.get(id=7), content='老郭没得话说。。') # 郭德纲 models.Comment.objects.create(object_id=1, content_type=ContentType.objects.get(id=8), content='这本书好神奇') # 傻子是这样炼成的
models.Comment.objects.create(object_id=2, content_type=ContentType.objects.get(id=8), content='永夜是什么夜') # 永夜
models.Comment.objects.create(object_id=3, content_type=ContentType.objects.get(id=8), content='武媚娘 武则天') # 武则天传奇
在新增评论表数据的时候我们会发现会有很繁琐的操作,例如我要给郭德纲评论,我需要先在 django_content_type 表中找到作者表,让 content_type 与之关联,再在作者表中找到郭德纲的主键,让其和 object_id 关联,最后才是评论内容。为了简化这种操作,contenttypes 给我们提供了 django.contrib.contenttypes.fields.GenericForeignKey 字段。修改 Comment 模型如下:
from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models from django.contrib.contenttypes.models import ContentType class Comment(models.Model):
'''
评论表
'''
content_type = models.ForeignKey(ContentType, on_delete=None) # 被评论表(对哪张表 进行评论)
object_id = models.PositiveIntegerField() # 被评论表中数据的id
content = models.CharField(max_length=200) # 评论内容
comment_to = GenericForeignKey('content_type', 'object_id') # 被评论对象
可以看到 Comment 模型中新增了一个 comment_to 字段,此时我们再来进行新增操作:
models.Comment.objects.create(comment_to=models.Author.objects.get(id=2), content='老郭 我又来了~!')
models.Comment.objects.create(comment_to=models.Book.objects.get(id=2), content='永远的夜晚?')
效果:
可以看到,相对于之前的新增操作,这里直接把要评论的对象赋值给 comment_to 字段,然后 contenttypes 会自动根据该对象的映射关系给 object_id 和 content_type 赋上值,不仅简化了操作,还让操作更加直观明了。
注意:这里添加的 comment_to 列仅仅用于操作,并不会在数据库生成对应列。
查询数据
正向查询
假如要查询出每条评论对应的评论对象,很显然我们需要先根据评论的 content_type 找到评论的对象类型(作者或书籍),然后从该对象类型对应的表中找到 pk 值为 object_id 值对应的那条数据。 django.contrib.contenttypes.fields.GenericForeignKey 字段除了给我们提供新增数据时的便利,查询数据的时候也是,如下:
for comment in models.Comment.objects.all():
print('{}=>{}'.format(comment.content,comment.comment_to))
效果:
可以看到每个评论的 comment_to 属性直接对应了评论的对象,是不是很给力~
反向查询
假如要查询出郭德纲(作者)和永夜(书籍)所有的评论,对于这种一对多的查询操作, contenttypes 给我们提供了另外一个字段—— django.contrib.contenttypes.fields.GenericRelation 。修改模型如下:
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
from django.db import models from django.contrib.contenttypes.models import ContentType class Book(models.Model):
title = models.CharField(max_length=32) # 书籍标题
comments = GenericRelation("Comment") # 所有评论 class Author(models.Model):
name = models.CharField(max_length=32) # 作者名称
comments = GenericRelation("Comment") # 所有评论 class Comment(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=None) # 被评论表(对哪张表 进行评论)
object_id = models.PositiveIntegerField() # 被评论表中数据的id
comment_to = GenericForeignKey('content_type', 'object_id') # 被评论对象
content = models.CharField(max_length=200) # 评论内容
如上,给模型 Book 和 Author 个各添加了一个 comments 字段,都对应 Comment 模型,此时我们完成上述要求的查询就很简单了,如下:
print('作者【郭德纲】的评论:')
[print(' '+comment.content) for comment in models.Author.objects.get(name='郭德纲').comments.all()]
print('书籍【永夜】的评论:')
[print(' '+comment.content) for comment in models.Book.objects.get(title='永夜').comments.all()]
效果:
注意:这里添加的 comments 列与上面加的 comment_to 列一样,都不会在数据库中生成对应列。
python框架之Django(15)-contenttype模块的更多相关文章
- python框架之Django(14)-rest_framework模块
APIView django原生View post请求 from django.shortcuts import render, HttpResponse from django import vie ...
- 第六篇:web之python框架之django
python框架之django python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django te ...
- python框架之django
python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django temple django models ...
- Python框架之Django学习
当前标签: Django Python框架之Django学习笔记(十四) 尛鱼 2014-10-12 13:55 阅读:173 评论:0 Python框架之Django学习笔记(十三) 尛 ...
- Python框架之Django的相册组件
Python框架之Django的相册组件 恩,没错,又是Django,虽然学习笔记已经结贴,但是学习笔记里都是基础的,Django的东西不管怎么说还是很多的,要学习的东西自然不会仅仅用十几篇博文就能学 ...
- Python框架之Django学习笔记(十一)
话说上次说到数据库的基本访问,而数据库我们主要进行的操作就是CRUD,也即是做计算处理时的增加(Create).读取(Retrieve)(重新得到数据).更新(Update)和删除(Delete),俗 ...
- python框架之Django(12)-认证系统之auth模块
我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Django作为一个完美主义者的终极框 ...
- Python高级进阶(一)Python框架之Django入门
传说中的Django Django由来 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的框架模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下 ...
- python框架之Django(1)-第一个Django项目
准备 自己写一个简单的webServer import socket # 生成socket实例对象 sk = socket.socket() # 绑定IP和端口 sk.bind(("127. ...
随机推荐
- spring事务的传播机制新解
以下是事物的传播机制: @Transactional(propagation=Propagation.REQUIRED)如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)@Transacti ...
- k8s 官方 配置文件使用教程
官网链接为 https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/#create-a-name ...
- 高性能前端 art-template 模板
官网: https://aui.github.io/art-template/zh-cn/index.html nodejs 服务器端使用 第一步: 引入 art-template 的包 npm in ...
- 一致性 Hash 学习与实现
普通的 Hash 解决的是什么问题? 下图是一个普通的余数法构造的哈希表. 一般在编程中使用哈希表,某个 bucket 突然就没了的概率比较小,常见的是因为负载因子太大需要增加 bucket,然后 r ...
- 【转】C# 高性能 TCP 服务的多种实现方式
原文链接: http://www.cnblogs.com/gaochundong/p/csharp_tcp_service_models.html 开源库: https://github.com/ga ...
- 一文弄懂神经网络中的反向传播法(Backpropagation algorithm)
最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...
- PowerDesigner 中模型设计导出Excel表格
今天项目做设计,客户要看数据设计,需要到处Excel表格.去网上搜索下,把使用总结如下: 已经完成设计的pd设计 打开pd,快捷键Ctrl + Shift + X或者Tools>Exectue ...
- C# 多线程中经常访问同一资源可能造成什么问题?
竞态条件和死锁. 如果两个或多个线程访问相同的对象,或者访问不同步的共享状态 ,就会出现竞态条件: 为了避免出现该问题,可以锁定共享的对象.但是过多的锁定也会有麻烦,那就是死锁: 当至少有两个线程被挂 ...
- flume学习笔记——安装和使用
Flume是一个分布式.可靠.和高可用的海量日志聚合的系统,支持在系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力. Flume是一 ...
- python把文件从一个目录复制到另外一个目录,并且备份
#!/usr/bin/python # -*- coding: utf-8 -*- import os,sys,md5,datetime,shutil,time,zipfile,chardet # c ...