添加標簽功能
在實現(xiàn)你的評論系統(tǒng)之后刷喜,你需要創(chuàng)建一個方法去標注你的博客(就是貼標簽)蒸绩。你可以通過整合第三方Django 標簽 應用程序到你的項目中去 做這些。django-taggit
是一個可復用的 應用程序,主要為你提供 Tag
模型骡尽,以及一個很簡單的在任何模型中添加標簽的管理器。 你可以在這個鏈接看到它的源代碼擅编;
首先你需要pip
允許下面的代碼去安裝 django-taggit
pip install django_taggit==1.2.0
這是攀细,打開mysite
項目的settings.py
文件,并且在 INSTALLED_APPS
設置中添加 taggit
, 如下:
打開你 blog
應用程序的 models.py
文件沙咏,并且在Post
模型中添加一個 通過 django-taggit
提供的 TaggableManager
管理器辨图,使用下面的代碼:
from taggit.managers import TaggableManager
class Post(models.Model):
# ....
tags = TaggableManager()
這個 tags
管理器將允許你 從 Post
對象中添加,檢索肢藐,刪除標簽故河。
允許下面的命令為你模型的更改創(chuàng)建一個遷移:
python manage.py makemigrations blog
你將得到下面的輸出:
現(xiàn)在,運行下面的命令為 django-taggit
模型去創(chuàng)建數(shù)據(jù)庫必須的表吆豹,并且同步你模型的更改鱼的。
python manage.py migrate
你將看到一些輸出,表明這個遷移已經(jīng)被應用了痘煤,如下:
你的數(shù)據(jù)庫現(xiàn)在準備去使用 django-taggit
模型了凑阶。
讓我們?nèi)ヌ剿魅绾稳ナ褂?tags
管理器。通過 python manage.py shell
命令打開終端衷快,并且輸入下面的代碼宙橱。首先將將檢索到你的一個帖子。(這個 帖子的ID = 1):
>>> from blog.models import Post
>>> post = Post.objects.get(id=1)
這時蘸拔,去給它添加一些標簽师郑,并且檢索這些標簽,檢查它們是否被成功添加:
>>> post.tags.add('music', 'jazz', 'django')
>>> post.tags.all()
<QuerySet [<Tag: django>, <Tag: music>, <Tag: jazz>]>
最后调窍,移除一個標簽宝冕,并且再次檢查這個標簽列表:
>>> post.tags.remove('django')
>>> post.tags.all()
<QuerySet [<Tag: music>, <Tag: jazz>]>
比較簡單,對吧邓萨?運行 python manage.py runserver
命令再次去打開開發(fā)者服務器地梨,并且在你的瀏覽器中打開 http://127.0.0.1:8000/admin/taggit/tag/
你將看到taggit
應用程序的帶有Tag
對象列表的管理員頁面。
導航到 http://127.0.0.1:8000/admin/blog/post/缔恳, 點擊一個帖子去編輯他宝剖。 你將看到現(xiàn)在的帖子包含一個 性的 Tags 字段,如下歉甚,這里可以很簡單的編輯標簽:
現(xiàn)在诈闺,你需要去編輯你的 博客帖子去顯示標簽。打開 blog/post/list.html
模板铃芦,并且去添加下面的 HTML 代碼雅镊,在 帖子 標題之后襟雷。
<p class="tags">Tags: {{ post.tags.all|join:", " }}</p>
這個 join
摹本過濾器工作和 Python 字符串的 join()
方法工作相似,用給定的字符串連接元素仁烹。在瀏覽器中打開 http://127.0.0.1:8000/blog/耸弄。 你應該能在每一個 帖子 標題下面看到標簽列表。
下一步卓缰,你將編輯 post_list
視圖去讓用戶列出所有指定標簽的帖子计呈。打開你 blog
應用程序的 views.py
文件。從django-taggit
中導入 Tag
模型征唬,并且修改 post_list
使用一個可選的標簽過濾帖子捌显。如下:
from taggit.models import Tag
def post_list(request, tag_slug=None):
object_list = Post.published.all()
tag = None
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
object_list = object_list.filter(tags__in=[tag])
paginator = Paginator(object_list, 3) # 每 3 篇博客一頁
# .....
post_list
視圖現(xiàn)在工作如下:
- 它提供了一個
tag_slug
可選參數(shù),它有一個None
默認值总寒。這個參數(shù)將在 URL 中傳遞扶歪。 - 在視圖內(nèi)部,您構(gòu)建初始的查詢集摄闸,檢索所有已發(fā)布的帖子善镰,如果這里提供了 標簽 slug。你可以用 slug 使用
get_object_or_404()
快捷方式得到Tag
對象年枕。 - 然后炫欺,通過包含給定標記的文章來篩選文章列表,因為這是一個 多對多的關系熏兄,您必須根據(jù)給定列表中包含的標記篩選帖子品洛,在這個例子中,該元素只包含一個元素摩桶。使用
__in
字段進行查找桥状。多對多關系發(fā)生在一個模型的多個對象和另一個模型的多個對象之間的聯(lián)系。在你的應用程序中典格,一個帖子可以有多個標簽并且一個標簽可以關聯(lián)多個帖子岛宦。你可以學習更多創(chuàng)建多對多關系台丛。在第五章:在你的網(wǎng)站中分享內(nèi)容耍缴。你也可以在這個鏈接中發(fā)現(xiàn)更多有關的知識。
請記住挽霉,查詢集是惰性的防嗡。只有在呈現(xiàn)模板時對 post 列表進行循環(huán)時,才會計算用于檢索 post 的查詢集侠坎。
最后蚁趁,在視圖的底部修改 render()
函數(shù),通過 tag
變量渲染到模板中实胸, 這個視圖看起來像這個樣子:
def post_list(request, tag_slug=None):
object_list = Post.published.all()
tag = None
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
object_list = object_list.filter(tags__in=[tag])
paginator = Paginator(object_list, 3) # 每 3 篇博客一頁
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# 如果頁面不是整數(shù)他嫡,就返回第一頁
posts = paginator.page(1)
except EmptyPage:
# 如果頁面超出范圍番官,就提交結(jié)果的最后一頁
posts = paginator.page(paginator.num_pages)
return render(request,
'blog/post/list.html',
{'posts': posts,
'tag': tag,
'page': page})
打開你 blog
應用程序的 urls.py
文件,注釋掉基于類的 PoslListView
url 模式钢属。取消掉 post_list
視圖徘熔,如下:
path('', views.post_list, name='post_list'),
# path('', views.PostListView.as_view(), name='post_list'),
添加以下附加的URL模式來按標記列出文章:
path('tag/<slug:tag_slug>/',
views.post_list, name='post_list_by_tag'),
正如你所見的,兩個模式都指向了相同的視圖淆党,但是你使用名稱區(qū)分它們酷师。第一個模式調(diào)用 post_list
視圖 時沒有任何可選參數(shù)。第二個模式調(diào)用 post_list
視圖的時候使用了 tag_slug
參數(shù)染乌。你使用一個 slug
路徑轉(zhuǎn)換器 將 參數(shù)匹配為 帶有 ASCII 字母或數(shù)字的小寫字符串山孔,加上連字符和下劃線字符。
自從你使用了 post_list
視圖荷憋,編輯 blog/post/list.html
模板台颠,并且去使用 posts
對象 修改 分頁器:
{% include "pagination.html" with page=posts %}
在 {% for %}
循環(huán)之上添加下面這些行:
{% if tag %}
<h2> Posts tagged with "{{ tag.name }}" </h2>
{% endif %}
如果一個用戶訪問這個 博客,它將看到一個所有帖子的列表台谊。如果他們通過貼有特殊標簽的過濾帖子蓉媳,他們將看到他們正在過濾的標簽。
現(xiàn)在锅铅,改變標簽的顯示方式酪呻,如下:
<p class="tags">
Tags:
{% for tag in post.tags.all %}
<a href="{% url "blog:post_list_by_tag" tag.slug %}">
{{ tag.name }}
</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
在上面的代碼中,循環(huán)一個 post 的所有標記盐须,顯示一個到 URL 的自定義鏈接玩荠,以通過該標記篩選 post。你使用 {% url "blog:post_list_by_tag" tag.slug %}
,使用URL名稱和slug標記作為其參數(shù)贼邓。用逗號分隔標簽阶冈。
在你的瀏覽器中打開 http://127.0.0.1:8000/blog/,并且點擊任何一個 tag 鏈接塑径。您將看到使用該標記的文章列表女坑,如下: