1

上一篇‘博客系统’的博客还没有实现评论,按标签搜索、按日期搜索、按分类搜索的功能,这篇博客主要是对以上功能的增加。

增添评论

第一步:新建app:comment,在主setting.py中添加新app,修改主urls.py文件

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'',include('blog.urls')),
    url(r'',include('comments.urls')),

]

第二步:编写评论的数据库表单

from django.contrib.auth.models import User
from django.db import models

# Create your models here.
from blog.models import Post


class Comment(models.Model):
    user =models.ForeignKey(User,verbose_name='用户')
    email = models.EmailField(verbose_name='电子邮箱')
    text = models.TextField(max_length=255,verbose_name='评论正文')
    # auto_now_add=True 自动create_time为最新一次更改评论信息的时间
    create_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
    post = models.ForeignKey(Post)
    class Meta:
        verbose_name = '评论'
        verbose_name_plural = '评论'

    def __str__(self):
        return  self.text[:4]

第三步:编写评论的路由comment.urls.py和comment.views.py

# comment.views.py
from django.shortcuts import render, get_object_or_404,redirect

# Create your views here.
from blog.models import Post
from comments.forms import CommentForm


def post_comment(request, id):
    # 1. 获取用户选择的博客
    post = get_object_or_404(Post, id=id)
    # 2. 如果用户提交评论
    if request.method == 'POST':
        print(request.POST)
        form = CommentForm(request.POST)
        # 2.1 判断表单是否合法
        if form.is_valid():
            comment = form.save(commit=False)
            comment.post = post
            comment.save()
        # 2.2 如果不合法,则提交错误信息
        else:
            return render(request, 'blog/detail.html',
                          context={
                              'errors': form.errors
                          })
    # 3. 如果不是POST请求,访问用户详情页
    return redirect(post.get_url())
# comment.urls
from django.conf.urls import url, include
from django.contrib import admin

from comments import views

app_name = 'comment'
urlpatterns = [
    url(r'^comment/blog/(?P<id>\d+)/$',views.post_comment,name='post_comment'),
]

第四步:编写评论表单

# 同步与数据库评论的形式
from comments.models import Comment


class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['user','email','text']

第五步:修改HTML文件中关于评论的部分

<section class="comment-area" id="comment-area">
                        <hr>
                        <h3>发表评论</h3>
                        <form action="{% url 'comment:post_comment' post.id %}" method="post" class="comment-form">
                            {% csrf_token %}
                            <div class="row">
                                <div class="col-md-4">
                                    <label for="{{ form.user.id }}">{{ form.user.label }}</label>
                                    {{ form.user }}
                                </div>
                                <div class="col-md-4">
                                    <label for="{{ form.email.id }}">{{ form.email.label }}</label>
                                    {{ form.email }}
                                </div>
                                <div class="col-md-12">
                                    <label for="{{ form.text.id }}">{{ form.text.label }}</label>
                                    {{ form.text }}
                                    <button type="submit" class="comment-btn">发表</button>
                                </div>
                            </div>    <!-- row -->
                        </form>
                        <div class="comment-list-panel">
                            <h3>评论列表,共 <span>{{ comments.count }}</span> 条评论</h3>
                            <ul class="comment-list list-unstyled">
                                {% for comment in comments %}
                                    <li class="comment-item">
                                        <span class="nickname">{{ comment.user }}</span>
                                        <time class="submit-date"
                                              datetime="{{ comment.create_time }}">{{ comment.create_time }}</time>
                                        <div class="text">
                                            {{ comment.text }}
                                        </div>
                                    </li>
                                {% endfor %}

                            </ul>
                        </div>
                    </section>

图片描述
图片描述

自定义标签

实现按标签搜索、按日期搜索、按分类搜索的功能

第一步:自定义标签

  1. 准备(必需)工作:
在某个app下创建一个名为templatetags(必需,且包名不可变)的包。假设我们在名为blog的app下创建了一个templatetags的包,并在该包下创建了一个名为blog_tags的文件.
 确保settings文件中的INSTALLD_APPS内必须含有该app
 修改setting.py有关时间显示的部分

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

#如果setting中配置USE_TZ=True则输出的是UTC时间(naive time),
# 如果setting中配置USE_TZ=False,则该输出时间与datetime.datetime.now()完全相同
# USE_TZ = True
USE_TZ = False
2. 接下来在blog_tags文件中写入如下几行

from django import template

register = template.Library()
 3. 在模板中使用{% load %} 标签装载自定义标签或者装饰器
from django import template
from django.db.models import Count

from blog.models import Post, Category, Tag

register = template.Library()

@register.simple_tag
def get_recent_posts(num=3):
    return Post.objects.all().order_by('-create_time')[:num]


@register.simple_tag
def archives():

    return Post.objects.dates(field_name='create_time',
                              kind='month',
                              order='DESC')

@register.simple_tag
def get_category():
    return Category.objects.annotate(num_posts=Count('post')).filter(num_posts__gt=0)


@register.simple_tag
def get_tags():
    # return Tag.objects.all()
    return Tag.objects.annotate(num_posts = Count('post'))

第二步: 编写标签查找的路由和视图函数

路由

#blog.urls.py
from django.conf.urls import url

from django.contrib import admin

from blog import views

app_name = 'blog'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'blog/(?P<id>\d+)/$', views.detail, name='detail'),
    url(r'^archive/(?P<year>\d{4})/(?P<month>\d{1,2})/', views.archive, name='archive'),
    url(r'^category/(?P<id>\d+)/', views.category, name='category'),
    url(r'^tag/(?P<id>\d+)/', views.tag, name='tag'),
    url(r'^search', views.search, name='search')
]

视图函数

from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404

# Create your views here.
from markdown import markdown

from blog.models import Post, Tag
from comments.forms import CommentForm


def index(request):
    # return HttpResponse('ok index!')
    posts = Post.objects.all()
    return render(request,'blog/index.html',context={
        'posts':posts
    })
def detail(request,id):
    # return HttpResponse('ok,%s detail' %(id))
    post = Post.objects.get(id=id)
    post.add_views()
    form = CommentForm()
    comments = post.comment_set.all()
    post.body = markdown(post.body,
                         extensions=['markdown.extensions.extra',
                                     'markdown.extensions.codehilite',
                                     'markdown.extensions.toc', ],
                         output_format='html')
    return render(request,'blog/detail.html',context={
        'post':post,
        'comments':comments,
        'form':form,
    })
def archive(request,year,month):
    posts = Post.objects.filter(
        create_time__year=year,
        create_time__month=month
    ).order_by('-create_time')

    return  render(request,'blog/index.html',context={
        'posts':posts
    })


def category(request,id):
    posts = Post.objects.filter(category_id=id)
    return render(request,'blog/index.html',
                  context={
                      'posts':posts

                  })


def tag(request,id):
    tag = get_object_or_404(Tag,id=id)
    posts = Post.objects.filter(tags=tag).order_by('-create_time')
    return render(
        request, 'blog/index.html',
        context={
            'posts': posts

        }


    )


def search(request):
    query = request.GET.get('query',None)
    posts = Post.objects.filter(
        Q(title__icontains=query) |
        Q(body__icontains=query)
    )

    if not posts:
        return render(request,'blog/index.html',
                      context={
                          'posts':posts,
                          'message':'没有找到相关信息'
                      }
                      )
    else:
        return render(request, 'blog/index.html',
                      context={
                          'posts': posts

                      }
                      )

第三步:修改Html文件,仅截取部分代码

这里在博客详情页需要显示的是博客的结构(目录),添加显示目录的代码
修改视图函数

def detail(request,id):
    # return HttpResponse('ok,%s detail' %(id))
    post = Post.objects.get(id=id)
    post.add_views()
    form = CommentForm()
    comments = post.comment_set.all()
    # post.body = markdown(post.body,
    #                      extensions=['markdown.extensions.extra',
    #                                  'markdown.extensions.codehilite',
    #                                  'markdown.extensions.toc', ],
    #                      output_format='html')
    md = Markdown(
        extensions=['markdown.extensions.extra',
                    'markdown.extensions.codehilite',
                    'markdown.extensions.toc', ],
        output_format='html'
    )
    # Convert markdown to serialized XHTML or HTML.
    post.body = md.convert(post.body)
    post.toc = md.toc
    return render(request,'blog/detail.html',context={
        'post':post,
        'comments':comments,
        'form':form,

    })

右侧导航栏

{#     基模板       #}

   <aside class="col-md-4">
                {% block toc %}

                {% endblock %}
                <div class="widget widget-recent-posts">
                    <h3 class="widget-title">最新文章</h3>
                    <ul>
                        {% get_recent_posts as recent_posts %}
                        {% for post in recent_posts %}
                            <li>
                                <a href="{{ post.get_url }}">{{ post.title }}</a>
                            </li>
                        {% endfor %}
                    </ul>
                </div>
                <div class="widget widget-archives">
                    <h3 class="widget-title">归档</h3>

                    <ul>
                        {% archives as dates %}
                        {% for date in  dates %}
                            <li>
                                <a href="{% url 'blog:archive' date.year date.month %}">{{ date.year }}年 {{ date.month }}月</a>
                            </li>
                        {% endfor %}


                    </ul>
                </div>

                <div class="widget widget-category">
                    <h3 class="widget-title">分类</h3>

                    <ul>
                        {% get_category as categories %}
                        {% for category in categories %}

                            <li>
                                <a href="{% url 'blog:category' category.id %}">{{ category.name }}<span
                                        class="post-count">({{ category.num_posts }})</span></a>
                            </li>
                        {% endfor %}
                    </ul>
                </div>

                <div class="widget widget-tag-cloud">
                    <h3 class="widget-title">标签云</h3>
                    <ul>
                        {% get_tags as tags %}
                        {% for tag in  tags %}
                            <li>
                                <a href="{% url 'blog:tag' tag.id %}">{{ tag.name }}</a>
                            </li>
                        {% endfor %}
                    </ul>
                </div>

详情页添加博客目录

{# blog/detail.html #}
{% block toc %}
    <div><h3 class="widget-title">文章目录</h3>
        {{ post.toc | safe }}
    </div>
{% endblock %}
按类别查找

图片描述

按标签查找

图片描述

按时间查找

图片描述

显示博客目录

图片描述

分页

Django提供了一个新的类来帮助你管理分页数据,这个类存放在django/core/paginator.py.它可以接收列表、元组或其它可迭代的对象。

def index(request):
    all_posts = Post.objects.count()
    if all_posts % PER_PAGE != 0:
        page_nums = all_posts // PER_PAGE + 1
    else:
        page_nums = all_posts // PER_PAGE
    paginator = Paginator(Post.objects.all(),PER_PAGE)
    if  request.GET.get('page'):
        page = request.GET.get('page')
    else:
        page = 1
    try:
        posts = paginator.page(page)
    except (PageNotAnInteger,EmptyPage):
        posts = paginator.page(1)

        posts.has_previous()
        posts.has_next()
        posts.previous_page_number()
        posts.next_page_number()


    return render(request, 'blog/index.html',
                  context={
        'title':'博客首页',
        'posts':posts,
        'pages_num':page_nums,
    })
修改主页的html文件有关分页显示的部分
  <div class="pager">
            {% if posts.has_previous %}
                <a href="?page={{ posts.previous_page_number }}">上一页</a>
            {% else %}
                <a href="#">上一页</a>

            {% endif %}


            <span class="current">第 {{ posts.number }} 页 / 共 {{ pages_num }} 页</span>

            {% if posts.has_next %}
                <a href="?page={{ posts.next_page_number }}">下一页</a>

            {% else %}
                <a href="#">下一页</a>

图片描述


SheenStar
168 声望26 粉丝

祝你坚强