文档章节

DJANGO的CONTENTTYPES和GENERIC RELATIONS

 飞儿飞
发布于 2017/02/17 12:47
字数 1035
阅读 2
收藏 0
点赞 0
评论 0

最近在做帮@Brian做一个小项目,借助了 Mezzanine 这个Django的CMS系统。在 CMS 里大量用到了 Django 里的 Content Type 和 Generic Relations。虽然在Django的官方文档里有对此有还算详细的描述,但是相关的中文资料比较少。所以打算汇总一下,结合我的经验写一个小教程,重要的是给出一些例子,而不是干巴巴看说明。

假使我们要写一个 Django 版本的 WordPress ,要定义的 Model 会有 Post,Page和URL,在是在WP里最典型的3种内容形式。

from django.db import models

class Post(models.Model):
  title = models.CharField(max_length=100)
  pub_date = model.DateTimeField(auto_now_add=True)
  content = models.TextField()

class Url(models.Model):
  title = models.CharField(max_length=100)
  pub_date = models.DateTimeField(auto_now_add=True)
  url = models.URLField(blank=True, verify_exists=True)

这个时候我想在写一个 Comment 的 Model,因为不管是 Post 或者 URL 都可以允许被评论。如果之前没有接触过Generic Relations,真的无所适从。有可能会写两个Model,一个Post_comments和一个URL_comments,或者是在Comment的model里加入两组Foreign Key。

class Comment(models.Model):
  title = models.CharField(max_length=100)
  post = models.ForeignKey(Post, black=True, null=True)
  url = models.ForeignKey(Url, black=True, null=True)

估计写出这样的Model的话,想自杀的心都有了。引入正题,Generic Relation。我们希望创建一个Comment的Model适用于所有内容类型,不管是Post,URL或者Page。Generic Relation能帮我们实现这样的Model。

from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType

class Comment(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    content = models.CharField(max_length=1000)

在 Django 中,有一个记录了项目中所有 model 元数据的表,就是 ContentType。表中一条记录便对应着一个存在的model ,那么我们只要通过一个元数据表的 id 和一个具体数据表中的 id,便可以找到任何model中的任何记录。

Comment 中使用 GenericForeignKey() 来指向其它的 Model 实例。为了使用它,还需要在 Model 中定义content_type 和 object_id 才可以。其中 content_typ e来自 ContentType 这个 Model,记录 Comment 所指向的其他 Model 实例的名字。 object_id则是表示所指向的Model实例的id。

实际上根据上面的解释它只要有 content_type 和 object_id 两个字段就够了,不过我们总是需要亲自指定两个字段的值。而 GenericForeignKey 出现的目的就是要把这个过程给自动化了,只要给 content_object 赋一个对象,就会自动得根据这个对象的元数据 ,给 content_type 和 object_id 赋值了。
GenericForeignKey 的构造函数接受两个可选参数:
def __init__(self, ct_field=”content_type”, fk_field=”object_id”):
你可以在构造 GenericForeignKey 时指定另外的字段名称。

a = Post(title='post1')
a.save()
b = Url(title='url1')
b.save()
c = Comment(content_object=a, content="test1")
c.save()
c.content_object

d = Comment(content_object=b, content="test2")
d.save()
d.content_object
Comment.objects.all()

结果是[<Comment: test1>,  <Comment: test2>]

由于GenericForeignKey()不是普通的外键,如果我们想查找一个Post下的所有评论,没法用下面的这种方式

# This will fail
Comment.objects.filter(content_object=a)
# This will also fail
Comment.objects.get(content_object=a)

需要绕一步,略微复杂

a_type = ContentType.objects.get_for_model(a)
Comment.objects.filter(content_type__pk=a_type.id, object_id=a.id)

结果是[<Comment: test1>]

其实是有办法让这个很正常的查询变得简单一些,Django 提供了 Reverse generic relations 的机制。
重新改一下 Post 这个 Model

class Post(models.Model):
  title = models.CharField(max_length=100)
  pub_date = model.DateTimeField(auto_now_add=True)
  content = models.TextField()
  comments = generic.GenericRelation(Comment)

这样我们就给 Post 这个 Model 添加了一个“逆向”的 generic relationship。每个 Post 的实例都有了个 comments 的属性,用于检索与之有关的 comments。

a = Post(title='test2')
a.save()
c1 = Comment(content_object=a, content='comment1')
c1.save()
c2= Comment(content_object=a, content='comment2')
c2.save()
a.comments.all()

[<Comment: comment1>,  <Comment: comment2>]

这里有有一段总结,写的不错,我就不翻译了,直接粘贴过来。

A generic relationship is defined by two elements: a foreign key to the ContentType table, to determine the type of the related object, and an ID field, to identify the specific object to link to. Django uses these two elements to provide a content_object pseudo-field which, to the user, works similarly to a real ForeignKey field. And, again just like a ForeignKey, Django can helpfully provide a reverse relationship from the linked model back to the generic one, although you do need to explicitly define this using generic.GenericRelation to make Django aware of it.

Reference

Django 官方文档 The contenttypes framework

efficient generic relations

Generic Relation在django的使用

Django And Generic Relations

本文转载自:http://blog.chedushi.com/archives/6048

共有 人打赏支持
粉丝 2
博文 48
码字总数 3370
作品 0
保定
Django 1.9 beta 1 发布

Django 1.9 beta 1 发布,这是一个预览/测试包,可供了解未来发布的 Django 1.9 的一些新特性。 详细介绍请看:发行说明。 下载页面:1.9b1 Django 1.9 支持 Python 2.7,3.4 和 3.5。 正在...

oschina ⋅ 2015/10/21 ⋅ 3

Django 1.9 alpha 1 发布,1.9 新特性初探

Django 1.9 alpha 1 发布,这是 Django 1.9 的首个发布,是1.9 发布周期的第一个预览/测试包,供你探视 1.9 带来的新变化。更多介绍请看 1.9 alpha 1 发行说明。 此版本已经完全冻结特性,计...

oschina ⋅ 2015/09/24 ⋅ 11

Django-005视图与网址

Django中网址是写在 urls.py 文件中,用正则表达式对应 views.py 中的一个函数(或者generic类)。 子目录 AutoTestPlatForm中是一些项目的设置settings.py 文件,总的urls配置文件 urls.py 以...

丰_申 ⋅ 2016/03/15 ⋅ 0

执行python manage.py syncdb,报Unknown command: 'syncdb'

D:Python27Libsite-packagesdjangobinT_project>python manage.py syncdb Unknown command: 'syncdb' Type 'manage.py help' for usage. 解决方案: 在Django 1.9及未来的版本种使用migrate代......

icestick8586 ⋅ 2016/12/14 ⋅ 0

Django后台:少量代码,实现强大的网站后台

Django的后台只需要少量代码,就可以实现强大功能. 本文章以Django 1.8.4位版本测试,基于python3.4,Ubuntu 14.10.以root账户运行.以后台添加博客位例子. 1.新建一个名称为blogproject的账户,...

巴鲁 ⋅ 2015/09/28 ⋅ 0

新建模型数据时候提示找不到应用是咋回事?

MAC 10.10 PYTHON 2.7 DJANGO 1.7 setting: INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.co......

kuangmsn ⋅ 2014/10/29 ⋅ 1

Django中的URL配置和模板

Django中的URL配置 : 实例: urlpatterns = patterns('', # Example: # (r'^myweb/', include('myweb.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admind......

happyliferao ⋅ 2015/05/13 ⋅ 0

Django服务器启动时报错,求助 ,新手

E:pythonwebprojectpythonweb>python manage.py runserver Validating models... Unhandled exception in thread started by Traceback (most recent call last): File "C:Python26Libsite-p......

宝玉 ⋅ 2013/01/13 ⋅ 3

Error: No module named blog

Error: No module named blog 在是django1.4版本和以前版本不同的地方,因为1.4版本里面的工程目录变了,在创建一个mysite工程后,进去该工程文件夹你会发现里面还有个mysite文件夹。所以在配...

闵开慧 ⋅ 2012/09/27 ⋅ 0

Django的标准库django.contrib包介绍

Django.contrib是啥?它是一个强大的功能包,是Django的标准库。 Django的标准库存放在 django.contrib 包中。每个子包都是一个独立的附加功能包。 这些子包一般是互相独立的,不过有些djang...

掬一捧 ⋅ 2013/11/12 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

博客迁移到 https://www.jianshu.com/u/aa501451a235

博客迁移到 https://www.jianshu.com/u/aa501451a235 本博客不再更新

为为02 ⋅ 33分钟前 ⋅ 0

win10怎么彻底关闭自动更新

win10自带的更新每天都很多,每一次下载都要占用大量网络,而且安装要等得时间也蛮久的。 工具/原料 Win10 方法/步骤 单击左下角开始菜单点击设置图标进入设置界面 在设置窗口中输入“服务”...

阿K1225 ⋅ 今天 ⋅ 0

Elasticsearch 6.3.0 SQL功能使用案例分享

The best elasticsearch highlevel java rest api-----bboss Elasticsearch 6.3.0 官方新推出的SQL检索插件非常不错,本文一个实际案例来介绍其使用方法。 1.代码中的sql检索 @Testpu...

bboss ⋅ 今天 ⋅ 0

informix数据库在linux中的安装以及用java/c/c++访问

一、安装前准备 安装JDK(略) 到IBM官网上下载informix软件:iif.12.10.FC9DE.linux-x86_64.tar放在某个大家都可以访问的目录比如:/mypkg,并解压到该目录下。 我也放到了百度云和天翼云上...

wangxuwei ⋅ 今天 ⋅ 0

PHP语言系统ZBLOG或许无法重现月光博客的闪耀历史[图]

最近在写博客,希望通过自己努力打造一个优秀的教育类主题博客,名动江湖,但是问题来了,现在写博客还有前途吗?面对强大的自媒体站点围剿,还有信心和可能型吗? 至于程序部分,我选择了P...

原创小博客 ⋅ 今天 ⋅ 0

IntelliJ IDEA 2018.1新特性

工欲善其事必先利其器,如果有一款IDE可以让你更高效地专注于开发以及源码阅读,为什么不试一试? 本文转载自:netty技术内幕 3月27日,jetbrains正式发布期待已久的IntelliJ IDEA 2018.1,再...

Romane ⋅ 今天 ⋅ 0

浅谈设计模式之工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻...

佛系程序猿灬 ⋅ 今天 ⋅ 0

Dockerfile基础命令总结

FROM 指定使用的基础base image FROM scratch # 制作base image ,不使用任何基础imageFROM centos # 使用base imageFROM ubuntu:14.04 尽量使用官方的base image,为了安全 LABEL 描述作...

ExtreU ⋅ 昨天 ⋅ 0

存储,对比私有云和公有云的不同

导读 说起公共存储,很难不与后网络公司时代的选择性外包联系起来,但尽管如此,它还是具备着简单和固有的可用性。公共存储的名字听起来也缺乏专有性,很像是把东西直接堆放在那里而不会得到...

问题终结者 ⋅ 昨天 ⋅ 0

C++难点解析之const修饰符

C++难点解析之const修饰符 c++ 相比于其他编程语言,可能是最为难掌握,概念最为复杂的。结合自己平时的C++使用经验,这里将会列举出一些常见的难点并给出相应的解释。 const修饰符 const在c...

jackie8tao ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部