记得有人跟我说过,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. PHP常见的字符串方法

    PHP语言中的字符串函数也是一个比较易懂的知识.今天我们就为大家总结了将近12种PHP字符串函数,希望对又需要的朋友有所帮助,增加读者朋友的PHP知识库.   1.查找字符位置函数 strpos($s ...

  2. CS20 D LCA

    给出一棵树,许多询问,每次询问A,B,C三点,求一点使到三点距离最小,输出该点和最小值. 很明显就是求LCA,三种组合都求一次LCA,然后在里面选个距离和最小的就行了. 官方题解里面的代码求LCA是在 ...

  3. JS代码判断浏览器版本,支持IE6,IE7,IE8,IE9!三种方法!

    web开发的时候有时候会用到JS检测IE的版本,下面是检测Microsoft Internet Explorer版本的三种代码! 方法一: <script type="text/jav ...

  4. 图片src拼接后台返回ID

    本文地址:http://www.cnblogs.com/veinyin/p/8507403.html  在学习 CSS 时只了解了给固定地址,但是如果给的是一个需要拼接的地址就蒙了,以下是基于 Vue ...

  5. Linux服务-搭建NFS

    任务目标:二进制安装nfs,作为共享存储挂载在三台web的网站根目录下,在任意一台web上修改的结果,其余两台都可以看到 首先来安装NFS服务,NFS顾名思义,就是极品飞车,哦不!是网络文件服务的意思 ...

  6. 在window 8 或windows2012 上用命令行安装framework3.5 方法

    找到对应操作系统安装目录的sources文件夹下的sxs文件夹,拷贝到本地电脑,如F:盘 根目录下 CMD(管理员身份)命令: dism.exe /online /enable-feature /fe ...

  7. 【逆向知识】开发WinDBG扩展DLL

    如何开发WinDbg扩展DLL WinDbg扩展DLL是一组导出的回调函数,用于实现用户定义的命令.以便从内存转储中提取特定的信息.扩展dll由调试器引擎加载,可以在执行用户模式或内核模式调试时提供自 ...

  8. C# 执行固定个数任务自行控制进入线程池的线程数量,多任务同时但是并发数据限定

    思路来源:http://bbs.csdn.NET/topics/390819824,引用该页面某网友提供的方法. 题目:我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个. 原 ...

  9. 使用数据库管理工具打开MySql

    1.推荐使用软件:Navicat_Premium_11.0.10.exe.  下载地址:http://pan.baidu.com/s/1nu6mTF7 2.下载上面文件并安装. 3.打开Navicat ...

  10. 通过`__slots__` 节省RAM

    标签(空格分隔): Python进阶 python中,由于创建每个实例都会有成员,这些成员都会被保存在dict中,但是Python不能静态分配RAM,当创建实例时,因此dict的大小会比所需要的内存大 ...