Django中自定義標籤的使用

問題描述:

在Django開發中,我們增加一個功能的時候,如:評論功能,因爲需要在不同的頁面下實現展示評論和提交評論的功能,所以可能需要修改不同頁面對應的視圖函數,這樣極大的提高了代碼的維護成本。

問題解決:

這個時候,我們可以藉助Django的自定義標籤來實現評論的功能,把評論功能對應的數據操作放在標籤函數中去實現,這樣就可以減少代碼的耦合,降低維護成本。

自定義標籤的使用:

(1)評論Comment對應的model定義:
models.py

from django.db import models


# Create your models here.
class Comment(models.Model):
    STATUS_NORMAL = 1
    STATUS_DELETE = 0
    STATUS_ITEMS = (
        (STATUS_NORMAL, '正常'),
        (STATUS_DELETE, '刪除'),
    )

    # target = models.ForeignKey(Post, verbose_name='評論目標')
    target = models.CharField(max_length=100, verbose_name='評論目標')
    content = models.CharField(max_length=500, verbose_name='內容')
    nickname = models.CharField(max_length=50, verbose_name='暱稱')
    website = models.URLField(verbose_name='網站')
    email = models.EmailField(verbose_name='郵箱')
    status = models.PositiveIntegerField(default=STATUS_NORMAL, choices=STATUS_ITEMS,
                                         verbose_name='狀態')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='創建時間')

    class Meta:
        verbose_name = verbose_name_plural = '評論'
        ordering = ['-created_time']  # 根據created_time進行降序排序

    @classmethod
    def get_by_target(cls, target):
        return cls.objects.filter(target=target, status=cls.STATUS_NORMAL)

(2)評論對應的後臺配置:
admin.py

from django.contrib import admin

from .models import Comment


# Register your models here.
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
    list_display = ('target', 'nickname', 'content', 'website', 'created_time')

(3)評論表單form的定義,在comment應用目錄下,新建forms.py:
forms.py:

import mistune

from django import forms

from .models import Comment


class CommentForm(forms.ModelForm):
    nickname = forms.CharField(
        label='暱稱',
        max_length=50,
        widget=forms.widgets.Input(
            attrs={'class': 'form-control', 'style': "width: 60%;"}
        )
    )
    email = forms.CharField(
        label='Email',
        max_length=50,
        widget=forms.widgets.EmailInput(
            attrs={'class': 'form-control', 'style': "width: 60%;"}
        )
    )
    website = forms.CharField(
        label='網站',
        max_length=100,
        widget=forms.widgets.URLInput(
            attrs={'class': 'form-control', 'style': "width: 60%;"}
        )
    )

    content = forms.CharField(
        label="內容",
        max_length=500,
        widget=forms.widgets.Textarea(
            attrs={'rows': 6, 'cols': 60, 'class': 'form-control'}
        )
    )

    # 對評論內容進行驗證
    def clean_content(self):
        content = self.cleaned_data.get('content')
        if len(content) < 1:
            raise forms.ValidationError('內容長度怎麼能這麼短呢!!')
        content = mistune.markdown(content)
        return content

    class Meta:
        model = Comment
        fields = ['nickname', 'email', 'website', 'content']

(4)創建comment自定義標籤,在在comment應用目錄下,新建templatetags目錄,在該目錄下新建__init__.py和comment_block.py文件。
在comment_block.py文件中編寫自定義標籤的代碼:
comment/templatetags/comment_block.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django import template

from comment.forms import CommentForm
from comment.models import Comment

register = template.Library()


@register.inclusion_tag('comment/block.html')
def comment_block(target):
    return {
        'target': target,
        'comment_form': CommentForm(),
        'comment_list': Comment.get_by_target(target)
    }

(5)編寫模板文件comment/block.html:
comment/block.html:
注意:因爲我們在後面的detail.html中引入了css文件:bootstrap.css,所以我們在block.html中使用了bootstrap.css中定義的一些樣式。

<hr/>
<div class="comment">
    <form class="form-group" action="/comment/" method="POST">
        {% csrf_token %}
        <input name="target" type="hidden" value="{{ target }}"/>
        {{ comment_form }}
        <input type="submit" value="submit">
    </form>
    <!--評論列表-->
    <ul class="list-group">
        {% for comment in comment_list %}
        <li class="list-group-item">
            <div class="nickname">
                <a href="{{ comment.website }}">{{ comment.nickname }}</a>
                <span>{{ comment.created_time}}</span>
            </div>
            <div class="comment-content">
                {{ comment.content }}
            </div>
        </li>
        {% endfor %}
    </ul>
</div>

(6)在其他頁面添加評論功能,如在文章詳情頁detail.html加入評論功能,
1、在detail.html的開頭引入評論的模板標籤:

{% load comment_block %}

2、在detail.html中需要引入評論的位置添加:

{% comment_block request.path post.title %}

即可引入評論的功能。
(7)在評論的form中(block.html),

<form class="form-group" action="/comment/" method="POST">

提交評論的時候,訪問了action="/comment/",所以需要在urls.py中配置該路徑對應的URL,並且在該URL對應的視圖函數中,對評論的數據進行驗證和保存。
1、urls.py代碼:

"""typeidea URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin

from blog.views import (
    IndexView, CategoryView, TagView,
    PostDetailView
)
from comment.views import CommentView

urlpatterns = [
    url(r'^$', IndexView.as_view(), name='index'),  # 首頁
    url(r'^category/(?P<category_id>\d+)/$', CategoryView.as_view(), name='category-list'),  # 分類列表頁
    url(r'^tag/(?P<tag_id>\d+)/$', TagView.as_view(), name='tag-list'),  # tag列表頁
    url(r'post/(?P<post_id>\d+).html$', PostDetailView.as_view(), name='post-detail'),  # 文章詳情頁
    url(r'^comment/$', CommentView.as_view(), name='comment'),  # 評論提交

    url(r'^admin/', admin.site.urls),
]

2、實現視圖函數comment/views.py:

from django.shortcuts import redirect
from django.views.generic import TemplateView

from .forms import CommentForm


class CommentView(TemplateView):
    http_method_names = ['post']
    template_name = 'comment/result.html'

    def post(self, request, *args, **kwargs):
        comment_form = CommentForm(request.POST)
        target = request.POST.get('target')

        if comment_form.is_valid():
            instance = comment_form.save(commit=False)
            instance.target = target
            instance.save()
            succeed = True
            return redirect(target)  # 評論成功,返回原評論頁面
        else:
            succeed = False

        context = {
            'succeed': succeed,
            'form': comment_form,
            'target': target
        }
        return self.render_to_response(context)  # 提交數據失敗,則去到評論結果頁comment/result.html。

3、評論結果頁comment/result.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>評論結果頁</title>
    <style>
        body {TEXT-ALIGN: center;}
        .result {
            text-align: center;
            width: 40%;
            margin: auto;
        }
        .errorlist {color: red;}
        ul li {
            list-style-type: None;
        }
    </style>
</head>
<body>
<div class="result">
    {% if succeed %}
    評論成功!
    <a href="{{ target }}">返回</a>
    {% else %}
    <ul class="errorlist">
        {% for field, message in form.errors.items %}
        <li>字段{{ field }}:{{ message }}</li>
        {% endfor %}
    </ul>
    <a href="javascript:window.history.back();">返回</a>
    {% endif %}
</div>
</body>
</html>

(8)結果演示:
文章詳情頁:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章