「標籤」是做者從文章中提取的核心詞彙,其餘用戶能夠經過標籤快速瞭解文章的關注點。每一篇文章的標籤可能都不同,而且還可能擁有多個標籤,這是與欄目功能不一樣的。html
好在標籤功能也有優秀的三方庫:Django-taggit,免得本身動手設計了。快速開發就是這樣,能「借用」就不要本身重複勞動。python
首先在虛擬環境中安裝Django-taggit:git
pip install django-taggit
安裝成功後,修改項目設置以添加庫:github
my_blog/settings.py ... INSTALLED_APPS = [ ... 'taggit', ] ...
標籤是文章Model的屬性,所以須要修改文章模型。django
須要注意的是標籤引用的不是內置字段,而是庫中的TaggableManager
,它是處理多對多關係的管理器:bootstrap
article/models.py ... # Django-taggit from taggit.managers import TaggableManager ... class ArticlePost(models.Model): ... # 文章標籤 tags = TaggableManager(blank=True) ...
而後記得數據遷移。bash
修改文章的表單類,讓其可以提交標籤字段:服務器
article/forms.py ... class ArticlePostForm(forms.ModelForm): class Meta: ... fields = ('title', 'body', 'tags')
而後修改發表文章的視圖,保存POST中的標籤:函數
article/views.py ... def article_create(request): # 已有代碼 if request.method == "POST": article_post_form = ArticlePostForm(data=request.POST) if article_post_form.is_valid(): new_article = article_post_form.save(commit=False) ... new_article.save() # 新增代碼,保存 tags 的多對多關係 article_post_form.save_m2m() ...
須要注意的是,若是提交的表單使用了commit=False
選項,則必須調用save_m2m()
才能正確的保存標籤,就像普通的多對多關係同樣。post
最後就是在發表文章的模板中添加標籤的表單項了:
templates/article/create.html ... <!-- 提交文章的表單 --> <form method="post" action="."> ... <!-- 文章標籤 --> <div class="form-group"> <label for="tags">標籤</label> <input type="text" class="form-control col-3" id="tags" name="tags" > </div> ... </form> ...
運行服務器,就能夠在發表頁面看到效果了:
多個標籤最好用英文逗號進行分隔。中文逗號有的版本會報錯,乾脆就不要去使用了。
雖然保存標籤的功能已經實現了,還得把它顯示出來才行。
顯示標籤最經常使用的位置是在文章列表中,方便用戶篩選感興趣的文章。
修改文章列表的模板,將標籤顯示出來:
templates/article/list.html ... <!-- 欄目 --> ... <!-- 標籤 --> <span> {% for tag in article.tags.all %} <a href="#" class="badge badge-secondary" > {{ tag }} </a> {% endfor %} </span> ...
連接中的class
中是Bootstrap定義的徽章樣式。
插入位置緊靠在欄目按鈕的後面。固然你想放到其餘位置也是徹底能夠的。
刷新列表頁面看看效果:
有時候用戶想搜索帶有某一個標籤的全部文章,如今就來作這個功能。
與搜索功能同樣,只須要調取數據時用filter()
方法過濾結果就能夠了。
修改<a>
標籤中的href
,使其帶有tag
參數返回到View中:
templates/article/list.html ... <!-- 標籤 --> <span> {% for tag in article.tags.all %} <a href="{% url 'article:article_list' %}?tag={{ tag }}" class="badge badge-secondary" > {{ tag }} </a> {% endfor %} </span> ...
而後在View中取得tag
的值,並進行搜索。
下面的代碼將article_list()
函數完整寫出來了(包括上一章末尾沒講的欄目查詢),方便讀者比對。
article/views.py ... def article_list(request): # 從 url 中提取查詢參數 search = request.GET.get('search') order = request.GET.get('order') column = request.GET.get('column') tag = request.GET.get('tag') # 初始化查詢集 article_list = ArticlePost.objects.all() # 搜索查詢集 if search: article_list = article_list.filter( Q(title__icontains=search) | Q(body__icontains=search) ) else: search = '' # 欄目查詢集 if column is not None and column.isdigit(): article_list = article_list.filter(column=column) # 標籤查詢集 if tag and tag != 'None': article_list = article_list.filter(tags__name__in=[tag]) # 查詢集排序 if order == 'total_views': article_list = article_list.order_by('-total_views') paginator = Paginator(article_list, 3) page = request.GET.get('page') articles = paginator.get_page(page) # 須要傳遞給模板(templates)的對象 context = { 'articles': articles, 'order': order, 'search': search, 'column': column, 'tag': tag, } return render(request, 'article/list.html', context) ...
注意Django-taggit中標籤過濾的寫法:filter(tags__name__in=[tag])
,意思是在tags
字段中過濾name
爲tag
的數據條目。賦值的字符串tag
用方括號包起來。
之因此這樣寫是由於Django-taggit還支持多標籤的聯合查詢,好比:
Model.objects.filter(tags__name__in=["tag1", "tag2"])
爲了實現帶參數的交叉查詢,還要將翻頁等位置的href
修改一下:
templates/article/list.html ... <!-- 全部相似地方加上 tag 參數,如排序、翻頁等 --> <a href="{% url 'article:article_list' %}?search={{ search }}&column={{ column }}&tag={{ tag }}"> 最新 </a> ... <a href="{% url 'article:article_list' %}?order=total_views&search={{ search }}&column={{ column }}&tag={{ tag }}"> 最熱 </a> ... <a href="?page=1&order={{ order }}&search={{ search }}&column={{ column }}&tag={{ tag }}" class="btn btn-success"> « 1 </a> <!-- 上面3條是舉例,其餘相似地方也請補充進去 --> ...
標籤過濾功能就完成了。
Django-taggit更多的用法請閱讀官方文檔:Django-taggit
本章學習了使用Django-taggit來完成標籤功能。
在學習階段,你能夠不借助他人的輪子,本身實現功能:瞎折騰對掌握基礎有很大幫助。
實際開發時,又分爲兩種狀況:
到底如何選擇,就根據你的喜歡進行斟酌了。