记得有人跟我说过,rails的has_many :through是一个”亮点“,在Django看来,该功能简直不值一提。rails中的many-to-many关联中,还需要你手工创建关联表(写 migration的方式),而has_many :through的”语法“只不过是为了自定义关联关系:通过一个中间的、到两端都是many-to-one的模型类实现多对多关联。

在Django中,many-to-many的中间关系表是自动创建的,如果你要指定一个自己的Model类作为关系对象,只需要在需要获取对端的
Model类中增加一个ManyToManyField属性,并指定though参数。比如现在我们已经有了这样两个many-to-one关
系,LineItem --->Product,  LineItem-->Order, 
如果需要从Product直接获取关联的Order,只需要增加一行,最终的Product如下:

class Product(models.Model):
title = models.CharField(max_length=,unique=True)
description = models.TextField()
image_url = models.URLField(max_length=)
price = models.DecimalField(max_digits=,decimal_places=)
date_available = models.DateField()
orders = models.ManyToManyField(Order,through='LineItem')

之后就可以通过product对象直接找到包含该产品的订单:

$ python manage.py shell
>>> from depot.depotapp.models import Product
>>> p = Product(id=)
>>> p.orders >>> p.orders.all()
[, ]

实现这个关系的目的是我们要针对每个产品生成一个”订阅“,用于查看谁买了该产品。我们采用Atom作为格式的标准。生成的Atom发布格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<id>tag:localhost,:/products//who_bought</id>
<link type="text/html" href="http://localhost:3000/depotapp" rel="alternate"/>
<link type="application/atom+xml" href="http://localhost:8000/depotapp/product/3/who_bought" rel="self"/>
<title>谁购买了《黄瓜的黄 西瓜的西》</title>
<updated>-- ::</updated>
<entry>
<id>tag:localhost,:Order/</id>
<published>-- ::</published>
<updated>-- ::</updated>
<link rel="alternate" type="text/html" href="http://localhost:8000/orders/1"/>
<title>订单1</title>
<summary type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>我住在北京</p>
</div>
</summary>
<author>
<name>我是买家</name>
<email>wanghaikuo@gmail.com</email>
</author>
</entry>
<entry>
<id>tag:localhost,:Order/</id>
<published>-- ::</published>
<updated>-- ::</updated>
<link rel="alternate" type="text/html" href="http://localhost:8000/orders/3"/>
<title>订单3</title>
<summary type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>我住在哪里?</p>
</div>
</summary>
<author>
<name>我是买家2</name>
<email>2222b@baidu.com</email>
</author>
</entry>
</feed>

你可能想到,Atom是以xml为格式的,我们可以借助Django REST framework来 实现,但是这不是一个好主意,因为REST framework生成的xml有其自身的格式,与Atom的格式完全不同。如果使用REST framework就需要对其进行定制,甚至要实现一个自己的renderer(比如,AtomRenderer),而这需要深入了解该框架的大量细节。 为了简单起见,我们考虑用Django的模板来实现。

首先我们设计url为:http://localhost:8000/depotapp/product/[id]/who_bought,先在depot/depotapp/urls.py中增加urlpatterns:

(r'product/(?P[^/]+)/who_bought$', atom_of_order)

然后在depot/depotapp/views.py中实现视图函数:

def atom_of_order(request,id):
product = Product.objects.get(id = id)
t = get_template('depotapp/atom_order.xml')
c=RequestContext(request,locals())
return HttpResponse(t.render(c), mimetype='application/atom+xml')

注意其中我们指定了mimetype,使浏览器知道返回的是xml而不是html。最后的工作就是编写模板了。depot/templates/depotapp/atom_order.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<id>tag:localhost,:/product/{{product.id}/who_bought</id>
<link type="text/html" href="{% url depotapp.views.store_view %}" rel="alternate"/>
<link type="application/atom+xml" href="{% url depotapp.views.atom_of_order product.id %}" rel="self"/>
<title>谁购买了《{{product.title}}》</title>
<updated>-- ::</updated>
{% for order in product.orders.all %}
<entry>
<id>tag:localhost,:order/{{order.id}}</id>
<published>-- ::</published>
<updated>-- ::</updated>
<link rel="alternate" type="text/html" href="{% url depotapp.views.atom_of_order order.id %}"/>
<title>订单{{order.id}}</title>
<summary type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>{{order.address}}</p>
</div>
</summary>
<author>
<name>{{order.name}}</name>
<email>{{order.email}}</email>
</author>
</entry>
{% endfor %}
</feed>

用模板实现Atom发布,确实很简单,不是吗?

Django实战(19):自定义many-to-many关系,实现Atom订阅的更多相关文章

  1. Django关于设置自定义404和安装debug-toolbar的笔记

    Django关于设置自定义404和安装debug-toolbar的笔记 关于设置404 先做好404页面,然后在views.py文件中做好映射,最后是在urls.py做好路由,而这个urls.py必须 ...

  2. 【SpringBoot】单元测试进阶实战、自定义异常处理、t部署war项目到tomcat9和启动原理讲解

    ========================4.Springboot2.0单元测试进阶实战和自定义异常处理 ============================== 1.@SpringBoot ...

  3. 第三百一十四节,Django框架,自定义分页

    第三百一十四节,Django框架,自定义分页 自定义分页模块 #!/usr/bin/env python #coding:utf-8 from django.utils.safestring impo ...

  4. [实战]MVC5+EF6+MySql企业网盘实战(19)——BJUI和ztree

    写在前面 上周在博客园看到一篇通用权限系统的文章,看到他那个UI不错,这里就研究了一下,将网盘的UI修改为他的那个,感兴趣的可以参考:http://b-jui.com/ 系列文章 [EF]vs15+e ...

  5. Django(模板语言-自定义filter和simple_tag)

    Django(模板语言-自定义filter和simple_tag)   filter过滤器的主要形式:变量|函数,意思是将变量交给函数处理,而自定义filter就是自己定义函数,因为用到已有的很少. ...

  6. 从零开始部署Django生产环境(适用:《跟老齐学Python Django实战》)

    <跟老齐学Python Django实战>作为市面上少有的Django通俗实战书籍,给了我学习Django很大的帮助.作为一名新入门的菜鸟,全书我重复练习了至少三遍,每次都有新的收获. 前 ...

  7. Django中的自定义过滤器

    一.为什么要自定义Django中的自定义过滤器:Django中提供了很多内置的过滤器和标签,详见链接django官网,主要有以下几个: autoescape(自动转义)block(模板继承)csrf_ ...

  8. Django模板之自定义过滤器/标签/组件

    自定义步骤: 1.     在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag. 2.     在app应用中创建templatet ...

  9. 19、Django实战第19天:课程列表页

    从今天开始,我们将完成"公开课"课程的相关功能..... 1.把course-list.html复制到templates目录下 2.这个页面的头部.底部与之前定义的base.htm ...

随机推荐

  1. UIScrollView的contentSize与contentOffset

    UIScrollView为了显示多于一个屏幕的内容或者超过你能放在内存中的内容. Scroll View为你处理缩小放大手势,UIScrollView实现了这些手势,并且替你处理对于它们的探测和回应. ...

  2. 安装并使用 Wowza 发布你的 RTMP 直播流

    转载自:http://blog.csdn.net/defonds/article/details/11979095 I. 下载 Wowza         官方下载地址 http://www.wowz ...

  3. AAC音频格式详解

    关于AAC音频格式基本情况,可参考维基百科http://en.wikipedia.org/wiki/Advanced_Audio_Coding AAC音频格式分析 AAC音频格式有ADIF和ADTS: ...

  4. Spark记录-Scala介绍

    Scala是可扩展语言的缩写,是一种混合功能编程语言. 它由Martin Odersky创建. Scala顺利整合面向对象和函数式语言的功能. Scala被编译后在Java虚拟机上运行. 许多现有公司 ...

  5. 100 Most Popular Machine Learning Video Talks

    100 Most Popular Machine Learning Video Talks 26971 views, 1:00:45,  Gaussian Process Basics, David ...

  6. wait&waitpid状态值

    [wait&waitpid状态值] 1.  python 中 os.system 的返回值的format与wait的返回值status一致: On Unix, the return value ...

  7. vue dev开发环境跨域和build生产环境跨域问题解决

    dev开发时解决请求跨域问题:config-index.js 配置代理dev: { env: require('./dev.env'), port: 8082, assetsSubDirectory: ...

  8. js工作常见问题收集

    1. viewport <meta name="viewport" content="width=device-width,initial-scale=1.0,mi ...

  9. UNIX环境高级编程 第9章 进程关系

    在第8章学习了进程的控制原语,通过各种进程原语可以对进程进行控制,包括新建进程.执行新程序.终止进程等.在使用fork( )产生新进程后,就出现了进程父子进程的概念,这是进程间的关系.本章更加详细地说 ...

  10. 【多视图几何】TUM 课程 第3章 透视投影

    课程的 YouTube 地址为:https://www.youtube.com/playlist?list=PLTBdjV_4f-EJn6udZ34tht9EVIW7lbeo4 .视频评论区可以找到课 ...