Django 多对多查询

2015-05-19

ManyToManyField

Django 框架中外键就是 QuerySet 对象,刚开始我一直没明白很多复杂的查询在 Django 里面怎么实现,昨天在 StackOverflow 上问了下,果然就搞明白了,这下有的就好办多了:

models.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.db import models


# Create your models here.
class Tag(models.Model):
tag_name = models.CharField(max_length=64)

def __unicode__(self):
return self.tag_name


class Article(models.Model):
title = models.CharField(max_length=100)
category = models.CharField(max_length=50)
tag = models.ManyToManyField(Tag, blank=True)
publish_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
content = models.TextField()

def __unicode__(self):
return self.title

一篇文章有多个标签,Article 表中 tag 字段是 Tag 表的多对多外键,我要在文章列表做首页的地方怎么把每篇文章的标签全列出来我就不明白了,在 views.py 里面能通过 id 先把这篇文章取出来,再把对应的 tag 取出来,两个参数列表传到模板中进行渲染:post = Article.objects.get(id=str(id)) tags = post.tag.all(),这个倒是能理解。

views.py

1
2
3
4
5
6
7
8
9
10
11
def home(request):
posts = Article.objects.all().order_by('-publish_time')
paginator = Paginator(posts, 4)
page = request.GET.get('page')
try:
post_list = paginator.page(page)
except PageNotAnInteger:
post_list = paginator.page(1)
except EmptyPage:
post_list = paginator.paginator(paginator.num_pages)
return render(request, 'home.html', {'post_list': post_list})

这里只把全部文章取出来,然后按发布时间倒序排列,还进行了分页,四篇一页,放在 post_list 这个参数列表中,然后在给 home.html 渲染:

home.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{% raw %}
{% block content %}
<div class="blog-post">
{% for post in post_list %}
<h2 class="blog-post-title"><a href="{% url 'detail' id=post.id %}">{{ post.title }}</a></h2>
<p class="blog-post-meta">
<span>发布时间:<a class="label label-primary">{{ post.publish_time | date:'Y/m/d' }}</a></span>
&nbsp&nbsp&nbsp&nbsp
<span>更新时间:<a class="label label-primary">{{ post.update_time | date:'Y/m/d' }}</a></span>
&nbsp&nbsp&nbsp&nbsp
<br />
<span>目录:&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp<a class="label label-primary" href="{% url 'category' post.category %}">{{ post.category | title}}</a></span>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
<span>标签:&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
{% for tag in post.tag.all %}
<a class="label label-primary" href="">{{ tag }}</a></span>
{% endfor %}
</p>

<p>
{{ post.content|custom_markdown | truncatewords:5}}
</p>

<h3>
<a class="label label-primary" href="{% url 'detail' id=post.id %}">Read More >>> </a>
</h3>
<br /><br />
{{"{% endfor "}}%}

{% if post_list.object_list and post_list.paginator.num_pages > 1 %}
<div>
<ul class="pager">
{% if post_list.has_previous %}
<li><a href="?page={{ post_list.previous_page_number }}">上一页</a></li>
{% endif %}

{% if post_list.has_next %}
<li><a href="?page={{ post_list.next_page_number }}">下一页</a></li>
{% endif %}
</ul>
</div>
{% endif %}
</div><!-- /.blog-post -->
{% endblock %}
{% endraw %}

关键就在于:

1
2
3
4
5
6
{% raw %}
<span>标签:&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
{% for tag in post.tag.all %}
<a class="label label-primary" href="">{{ tag }}</a></span>
{% endfor %}
{% endraw %}

最开始已经把每篇文章通过 for 循环放在 post 里面了,想读单独一篇的文章的标签就再用 for 循环 for tag in post.tag.all

还是要多看文档……