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)结果演示:
文章详情页:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值