Django实战(19):自定义many-to-many关系,实现Atom订阅

记得有人跟我说过,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=100,unique=True)
    description    = models.TextField()
    image_url = models.URLField(max_length=200)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    date_available = models.DateField()
    orders = models.ManyToManyField(Order,through='LineItem')

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

$ python manage.py shell
>>> from depot.depotapp.models import Product
>>> p = Product(id=1)
>>> p.orders
<django.db.models.fields.related.ManyRelatedManager object at 0x10be110>
>>> p.orders.all()
[<Order: Order object>, <Order: Order object>]

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

<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
	<id>tag:localhost,2005:/products/3/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>2012-01-02 12:02:02</updated> 
	<entry>
		<id>tag:localhost,2005:Order/1</id>
		<published>2012-01-02 12:02:02</published>
		<updated>2012-01-02 12:02:02</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,2005:Order/3</id>
		<published>2012-01-02 12:02:02</published>
		<updated>2012-01-02 12:02:02</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<id>[^/]+)/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,2005:/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>2012-01-02 12:02:02</updated> 
{% for order in product.orders.all %}
	<entry>
		<id>tag:localhost,2005:order/{{order.id}}</id>
		<published>2012-01-02 12:02:02</published>
		<updated>2012-01-02 12:02:02</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发布,确实很简单,不是吗?




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值