1. 程式人生 > >搭建自己的部落格(二十六):增加登入註冊以及個人資料按鈕

搭建自己的部落格(二十六):增加登入註冊以及個人資料按鈕

1、變化的部分

2、上程式碼:

{# 引用模板 #}
{% extends 'base.html' %}
{% load staticfiles %}
{% load comment_tags %}
{% load likes_tags %}

{% block header_extends %}
    <link rel="stylesheet" href="{% static 'blog/blog.css' %}">
    <link rel="stylesheet" href="{% static 'fontawesome-free-5.5.0-web/css/all.min.css' %}"
> {# 處理公式 #} <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script> <script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script> <script type="text/javascript"
src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script> {% endblock %} {# 標題 #} {% block title %} {{ blog.title }} {% endblock %} {# 內容#} {% block content %} <div class="container"> <div class="row"> <div class="col-10 offset-1">
<ul class="blog-info-description"> <h3>{{ blog.title }}</h3> <li>作者:{{ blog.author }}</li> {# 時間過濾器讓時間按照自己需要的格式過濾 #} <li>釋出日期:{{ blog.created_time|date:"Y-m-d H:i:s" }}</li> <li>分類: <a href="{% url 'blogs_with_type' blog.blog_type.pk %}"> {{ blog.blog_type }} </a> </li> <li>閱讀({{ blog.get_read_num }})</li> <li>評論({% get_comment_count blog %})</li> </ul> <div class="blog-content">{{ blog.content|safe }}</div> <div class="like" onclick="likeChange(this,'{% get_content_type blog %}',{{ blog.pk }})"> <i class="far fa-thumbs-up {% get_like_status blog %}"></i> <span class="liked-num">{% get_like_count blog %}</span> <span>喜歡</span> </div> <p>上一篇: {% if previous_blog %} <a href="{% url 'blog_detail' previous_blog.pk %}">{{ previous_blog.title }}</a> {% else %} <span>沒有了</span> {% endif %} </p> <p>下一篇: {% if next_blog %} <a href="{% url 'blog_detail' next_blog.pk %}">{{ next_blog.title }}</a> {% else %} <span>沒有了</span> {% endif %} </p> </div> </div> <div class="row"> <div class="col-10 offset-1"> <div class="comment-area"> <h3 class="comment-area-title">提交評論</h3> {% if user.is_authenticated %} <form id="comment-form" action="{% url 'update_comment' %}" method="post" style="overflow: hidden"> {% csrf_token %} <label for="form-control">{{ user.username }},歡迎評論~</label> <div id="reply-content-container" style="display: none;"> <p id="reply_title">回覆:</p> <div id="reply-content"> </div> </div> {% get_comment_form blog as comment_form %} {% for field in comment_form %} {{ field }} {% endfor %} <span id="comment-error" class="text-danger float-left"></span> <input type="submit" value="評論" class="btn btn-primary float-right"> </form> {% else %} 您尚未登入,登入之後方可評論 {# 提交登入的時候帶上從哪裡訪問的路徑 #} <a class="btn btn-primary" href="{% url 'login' %}?from={{ request.get_full_path }}">登入</a> <span> or </span> <a class="btn-danger btn" href="{% url 'register' %}?from={{ request.get_full_path }}">註冊</a> {% endif %} </div> <div class="-comment-area"> <h3 class="comment-area-title">評論列表</h3> <div id="comment-list"> {% get_comment_list blog as comments %} {% for comment in comments %} <div id="root-{{ comment.pk }}" class="comment"> <span>{{ comment.user.username }}</span> <span>{{ comment.comment_time|date:"Y-m-d H:i:s" }}</span> <div id="comment-{{ comment.pk }}">{{ comment.text|safe }}</div> {# 點贊 #} <div class="like" onclick="likeChange(this,'{% get_content_type comment %}',{{ comment.pk }})"> <i class="far fa-thumbs-up {% get_like_status comment %}"></i> <span class="liked-num">{% get_like_count comment %}</span> </div> <a href="javascript:reply({{ comment.pk }})">回覆</a> {% for reply in comment.root_comment.all %} <div class="reply"> <span>{{ reply.user.username }}</span> <span>{{ reply.comment_time|date:"Y-m-d H:i:s" }}</span> <span>回覆:</span><span>{{ reply.reply_to.username }}</span> <div id="comment-{{ reply.pk }}">{{ reply.text|safe }}</div> {# 點贊 #} <div class="like" onclick="likeChange(this,'{% get_content_type reply %}',{{ reply.pk }})"> <i class="far fa-thumbs-up {% get_like_status reply %}"></i> <span class="liked-num">{% get_like_count reply %}</span> </div> <a href="javascript:reply({{ reply.pk }})">回覆</a> </div> {% endfor %} </div> {% empty %} <span id="no-comment">暫無評論</span> {% endfor %} </div> </div> </div> </div> </div> {% endblock %} {% block js %} <script> // 處理點贊 function likeChange(obj, content_type, object_id) { let is_like = obj.getElementsByClassName('active').length === 0; $.ajax({ url: "{% url 'like_change' %}", type: 'GET', data: { content_type: content_type, object_id: object_id, is_like: is_like, }, cache: false, success: function (data) { console.log(data); if (data['status'] === 'SUCCESS') { // 更新點贊狀態 let element = $(obj.getElementsByClassName('fa-thumbs-up')); if (is_like) { element.addClass('active'); } else { element.removeClass('active'); } // 更新點贊數量 let like_num = $(obj.getElementsByClassName('liked-num')); like_num.text(data['liked_num']); } else { if (data['code'] === 400) { $('#login_model').modal('show'); } else { alert(data['msg']); } } }, error: function (xhr) { console.log(xhr); } }); } // 處理回覆 function reply(reply_comment_id) { $('#reply_comment_id').val(reply_comment_id); let html = $('#comment-' + reply_comment_id).html(); $('#reply-content').html(html); $('#reply-content-container').show(); // 顯示內容 // 滾動富文字編輯器 $('html').animate({scrollTop: $('#comment-form').offset().top - 60}, 300, function () { // 動畫執行完畢後執行的方法 // 讓富文字編輯器獲得焦點 CKEDITOR.instances['id_text'].focus(); }); } function numFormat(num) { return ('00' + num).substr(-2); } function timeFormat(timestamp) { let datetime = new Date(timestamp * 1000); let year = datetime.getFullYear(); let month = numFormat(datetime.getMonth() + 1); let day = numFormat(datetime.getDate()); let hour = numFormat(datetime.getHours()); let minute = numFormat(datetime.getMinutes()); let second = numFormat(datetime.getSeconds()); return `${year}-${month}-${day} ${hour}:${minute}:${second}` } // 提交評論 $('#comment-form').submit(function () { // 獲取錯誤框 let comment_error = $('#comment-error'); comment_error.text(''); // 更新資料到textarea CKEDITOR.instances['id_text'].updateElement(); let comment_text = CKEDITOR.instances['id_text'].document.getBody().getText().trim(); // 判斷是否為空 if (!(CKEDITOR.instances['id_text'].document.getBody().find('img')['$'].length !== 0 || comment_text !== '')) { // 顯示錯誤資訊 comment_error.text('評論內容不能為空'); return false; } //非同步提交 $.ajax({ url: "{% url 'update_comment' %}", type: 'POST', data: $(this).serialize(),// 序列化表單值 cache: false, // 關閉快取 success: function (data) { let reply_comment = $('#reply_comment_id'); if (data['status'] === 'SUCCESS') { console.log(data); // 插入資料 // es6寫法 let like_html = `<div class="like" onclick="likeChange(this,'${data['content_type']}',${data["pk"]})"> <i class="far fa-thumbs-up"></i> <span class="liked-num">0</span> </div>`; if (reply_comment.val() === '0') { // 插入評論 let comment_html = `<div id="root-${data["pk"]}" class="comment"> <span>${data["username"]}</span> <span>${timeFormat(data["comment_time"])}</span> <div id="comment-${data["pk"]}">${data["text"]}</div> ${like_html} <a href="javascript:reply(${data["pk"]})">回覆</a> </div>`; $('#comment-list').prepend(comment_html); } else { // 插入回覆 let reply_html = `<div class="reply"> <span>${data["username"]}</span> <span>${timeFormat(data["comment_time"])}</span> <span>回覆:</span><span>${data["reply_to"]}</span> <div id="comment-${data["pk"]}">${data["text"]}</div> ${like_html} <a href="javascript:reply(${data["pk"]})">回覆</a> </div>`; $('#root-' + data['root_pk']).append(reply_html); } // 清空編輯框的內容 CKEDITOR.instances['id_text'].setData(''); $('#reply-content-container').hide(); // 回覆完隱藏掉要回復的內容 reply_comment.val('0'); // 將回復標誌重置0 $('#no-comment').remove(); // 如果有沒回復標誌,清除掉5 comment_error.text('評論成功'); } else { // 顯示錯誤資訊 comment_error.text(data['message']) } }, error: function (xhr) { console.log(xhr); } }); return false; }); </script> <script> $(".nav-blog").addClass("active").siblings().removeClass("active"); </script> {% endblock %}
blog下的blog_detail.html
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator
from django.conf import settings
from django.db.models import Count
from read_statistics.utils import read_statistics_once_read
from .models import Blog, BlogType


# 分頁部分公共程式碼
def blog_list_common_data(requests, blogs_all_list):
    paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER)  # 第一個引數是全部內容,第二個是每頁多少
    page_num = requests.GET.get('page', 1)  # 獲取url的頁面引數(get請求)
    page_of_blogs = paginator.get_page(page_num)  # 從分頁器中獲取指定頁碼的內容

    current_page_num = page_of_blogs.number  # 獲取當前頁
    all_pages = paginator.num_pages
    if all_pages < 5:
        page_range = list(
            range(max(current_page_num - 2, 1),
                  min(all_pages + 1, current_page_num + 3)))  # 獲取需要顯示的頁碼 並且剔除不符合條件的頁碼
    else:
        if current_page_num <= 2:
            page_range = range(1, 5 + 1)
        elif current_page_num >= all_pages - 2:
            page_range = range(all_pages - 4, paginator.num_pages + 1)
        else:
            page_range = list(
                range(max(current_page_num - 2, 1),
                      min(all_pages + 1, current_page_num + 3)))  # 獲取需要顯示的頁碼 並且剔除不符合條件的頁碼

    blog_dates = Blog.objects.dates('created_time', 'month', order='DESC')
    blog_dates_dict = {}
    for blog_date in blog_dates:
        blog_count = Blog.objects.filter(created_time__year=blog_date.year, created_time__month=blog_date.month).count()
        blog_dates_dict = {
            blog_date: blog_count
        }

    return {
        'blogs': page_of_blogs.object_list,
        'page_of_blogs': page_of_blogs,
        'blog_types': BlogType.objects.annotate(blog_count=Count('blog')),  # 新增查詢並新增欄位
        'page_range': page_range,
        'blog_dates': blog_dates_dict
    }


# 部落格列表
def blog_list(requests):
    blogs_all_list = Blog.objects.all()  # 獲取全部部落格
    context = blog_list_common_data(requests, blogs_all_list)
    return render(requests, 'blog/blog_list.html', context)


# 根據型別篩選
def blogs_with_type(requests, blog_type_pk):
    blog_type = get_object_or_404(BlogType, pk=blog_type_pk)
    blogs_all_list = Blog.objects.filter(blog_type=blog_type)  # 獲取全部部落格
    context = blog_list_common_data(requests, blogs_all_list)
    context['blog_type'] = blog_type
    return render(requests, 'blog/blog_with_type.html', context)


# 根據日期篩選
def blogs_with_date(requests, year, month):
    blogs_all_list = Blog.objects.filter(created_time__year=year, created_time__month=month)  # 獲取全部部落格
    context = blog_list_common_data(requests, blogs_all_list)
    context['blogs_with_date'] = '{}年{}日'.format(year, month)
    return render(requests, 'blog/blog_with_date.html', context)


# 部落格詳情
def blog_detail(requests, blog_pk):
    blog = get_object_or_404(Blog, pk=blog_pk)
    obj_key = read_statistics_once_read(requests, blog)

    context = {
        'blog': blog,
        'previous_blog': Blog.objects.filter(created_time__gt=blog.created_time).last(),
        'next_blog': Blog.objects.filter(created_time__lt=blog.created_time).first(),
    }
    response = render(requests, 'blog/blog_detail.html', context)
    response.set_cookie(obj_key, 'true')

    return response
blog下的views.py
"""
Django settings for myblog project.

Generated by 'django-admin startproject' using Django 2.1.3.

For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ea+kzo_5k^[email protected]([email protected]*+w5d11=0mp1p5ngr'

# SECURITY WARNING: don't run with debug turned on in production!2.
DEBUG = True

ALLOWED_HOSTS = ['*']

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions'