python實戰----博客系統(完善)

上一篇‘博客系統’的博客尚未實現評論,按標籤搜索、按日期搜索、按分類搜索的功能,這篇博客主要是對以上功能的增長。html

增添評論

第一步:新建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')),

]

第二步:編寫評論的數據庫表單django

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.pymarkdown

# 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'),
]

第四步:編寫評論表單app

# 同步與數據庫評論的形式
from comments.models import Comment


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

第五步:修改HTML文件中關於評論的部分ide

<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>

圖片描述
圖片描述

自定義標籤

實現按標籤搜索、按日期搜索、按分類搜索的功能函數

第一步:自定義標籤post

  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'))

第二步: 編寫標籤查找的路由和視圖函數url

路由spa

#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>

圖片描述

相關文章
相關標籤/搜索