項目實戰:BBS+Blog項目開發

01-博客系統之功能需求

02-博客系統之表結構設計1

03-博客系統之表結構設計2

04-博客系統之表結構設計3

05-博客系統之表結構設計4

06-博客系統之表機構設計5

07-博客系統之建立系統與遷移表

08-博客系統之登陸頁面設計

09-博客系統之驗證碼圖片的生成1

10-博客系統之驗證碼圖片的生成2

11-博客系統之驗證碼圖片的噪點燥線

12-博客系統之驗證碼刷新

13-博客系統之保存驗證碼字符串

14-博客系統之登陸驗證

15-博客系統之登陸驗證代碼優化

16-博客系統之滑動驗證碼做業

17-博客系統之基於form組件的註冊頁面設計1

18-博客系統之註冊頁面的默認頭像

19-博客系統之註冊頁面的頭像預覽功能

20-博客系統之基於Ajax的form data數據

21-博客系統之基於Ajax提交from data的數據的優化

22-博客系統之基於Ajax在註冊頁面顯示錯誤消息1

23-博客系統之基於Ajax在註冊頁面顯示錯誤消息2

24-博客系統之form組件的局部鉤子與全局鉤子的應用

25-博客系統之FileFiled字段

26-博客系統之media配置1

27-博客系統之media配置2

28-博客系統之生成用戶對象的代碼優化

29-博客系統之系統首頁的導航區域

30-博客系統之系統首頁的主體佈局

31-博客系統之admin的簡單實用

32-博客系統之基於admin錄入文章數據

33-博客系統之系統首頁的文章列表的渲染1

34-博客系統之系統首頁的文章列表的渲染2

35-博客系統之我的站點的頁面文章的查詢

36-博客系統之我的站點頁面的標籤與分類查詢

37-博客系統之我的站點頁面的日期查詢1

38-博客系統之我的站點頁面的日期查詢2

39-博客系統之我的站點頁面的日期查詢3

40-博客系統之我的站點頁面的日期查詢4

41-博客系統之我的站點頁面的渲染布局1

42-博客系統之我的站點頁面的渲染布局2

43-博客系統之我的站點頁面的渲染布局3

44-博客系統之我的站點的跳轉過濾功能的實現1

45-博客系統之我的站點頁面的跳轉過濾功能實現2

46-博客系統之我的站點頁面的跳轉過濾功能的實現3

47-博客系統之文章詳情頁的設計

48-博客系統之文章詳情頁的構建

49-博客系統之文章詳情頁的inclution_tag

50-博客系統之文章詳情頁渲染標籤的標籤字符串轉義1

51-博客系統之文章詳情頁渲染的標籤字符串轉義2

52-博客系統之文章點贊樣式的構建

53-博客系統之文章點贊事件的綁定

54-博客系統之文章點讚的保存

55-博客系統之文章點贊數的數據同步

56-博客系統之文章點讚的提示重複操做

57-博客系統之文章點贊數的Ajax更新

58-博客系統之文章點贊代碼的優化

59-博客系統之評論功能的實現流程

60-博客系統之評論樣式

61-博客系統之提交根評論

62-博客系統之render顯示根評論

63-博客系統之Ajax顯示根評論

64-博客系統之回覆按鈕事件

65-博客系統之提交子評論

66-博客系統之render顯示

67-博客系統之Ajax顯示子評論的思路

68-博客系統之評論樹簡介

69-博客系統之評論樹的請求數據

70-博客系統之展開評論樹

71-博客系統之展開評論樹2

72-博客系統之評論樹的思考1

73-博客系統之評論樹的思考2

74-博客系統之評論事務操做

75-博客系統之評論的郵件發送new

76-博客系統以後臺管理頁面的編輯功能

77-博客系統以後臺管理的編輯器引入和參數

78-博客系統之文本編輯器的上傳功能1

79-博客系統之文本編輯器的上傳功能2

80-博客系統之文章摘要的保存

81-博客系統之bs4的簡單應用

82-博客系統之bs4模塊防護xss攻擊

01-博客系統之功能需求

一、項目開發流程;

  • 一、搞清楚需求(與產品經理對接);
  • 二、設計表結構;
  • 三、按照每個功能(需求)進行開發;

二、什麼是博客?

  • 博客園;
  • CSDN;
  • 微信朋友圈;
  • 新浪博客;
  • 新浪微博;

三、基礎功能分析;

  • 一、登陸-基於用戶認證組件和Ajax實現登陸驗證(圖片驗證碼);
  • 二、註冊-基於Ajax和form組件實現;
  • 三、設計系統首頁(文章列表的渲染);
  • 四、設計我的站點頁面;
  • 五、文章詳情頁;
  • 六、實現點贊功能(基於Ajax);
  • 七、實現文章評論功能(對子評論的評論);
  • 八、後臺管理頁面;
  • 九、富文本編輯框和防止XSS攻擊;

四、功能測試;

五、項目部署上線;

02-博客系統之表結構設計1

03-博客系統之表結構設計2

04-博客系統之表結構設計3

05-博客系統之表結構設計4

06-博客系統之表機構設計5

07-博客系統之建立系統與遷移表

一、註釋默認的sqllite數據庫,修改成MySQL數據庫;

二、編寫models.py;

from django.db import models

# Create your models here.


from django.contrib.auth.models import AbstractUser


class UserInfo(AbstractUser):
    """
    用戶信息
    """
    nid = models.AutoField(primary_key=True)
    telephone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png")
    create_time = models.DateTimeField(verbose_name='建立時間', auto_now_add=True)

    blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE)

    def __str__(self):
        return self.username


class Blog(models.Model):
    """
    博客信息
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='我的博客標題', max_length=64)
    site_name = models.CharField(verbose_name='站點名稱', max_length=64)
    theme = models.CharField(verbose_name='博客主題', max_length=32)

    def __str__(self):
        return self.title


class Category(models.Model):
    """
    博主我的文章分類表
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='分類標題', max_length=32)
    blog = models.ForeignKey(verbose_name='所屬博客', to='Blog', to_field='nid', on_delete=models.CASCADE)

    def __str__(self):
        return self.title


class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='標籤名稱', max_length=32)
    blog = models.ForeignKey(verbose_name='所屬博客', to='Blog', to_field='nid', on_delete=models.CASCADE)

    def __str__(self):
        return self.title


class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name='文章標題')
    desc = models.CharField(max_length=255, verbose_name='文章描述')
    create_time = models.DateTimeField(verbose_name='建立時間', auto_now_add=True)
    content = models.TextField()

    comment_count = models.IntegerField(default=0)
    up_count = models.IntegerField(default=0)
    down_count = models.IntegerField(default=0)

    user = models.ForeignKey(verbose_name='做者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
    category = models.ForeignKey(to='Category', to_field='nid', null=True, on_delete=models.CASCADE)
    tags = models.ManyToManyField(
        to="Tag",
        through='Article2Tag',
        through_fields=('article', 'tag'),
    )

    def __str__(self):
        return self.title


class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid', on_delete=models.CASCADE)
    tag = models.ForeignKey(verbose_name='標籤', to="Tag", to_field='nid', on_delete=models.CASCADE)

    class Meta:
        unique_together = [
            ('article', 'tag'),
        ]

    def __str__(self):
        v = self.article.title + "---" + self.tag.title
        return v


class ArticleUpDown(models.Model):
    """
    點贊表
    """

    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE)
    article = models.ForeignKey("Article", null=True, on_delete=models.CASCADE)
    is_up = models.BooleanField(default=True)

    class Meta:
        unique_together = [
            ('article', 'user'),
        ]


class Comment(models.Model):
    """

    評論表

    """
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='評論文章', to='Article', to_field='nid', on_delete=models.CASCADE)
    user = models.ForeignKey(verbose_name='評論者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
    content = models.CharField(verbose_name='評論內容', max_length=255)
    create_time = models.DateTimeField(verbose_name='建立時間', auto_now_add=True)
    parent_comment = models.ForeignKey('self', null=True, on_delete=models.CASCADE)

    def __str__(self):
        return self.content

三、settingsp.py添加AUTH_USER_MODEL=「blog.UserInfo」;

"""
Django settings for cnblogs project.

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

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 = '97e0#&=bl*0zl@99!_#4o*6fs=e&3-6@8rdq0clas*hojx6!5z'

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

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',

    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'cnblogs.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'cnblogs.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',#數據庫的引擎爲MySQL;
        'NAME': 'cnblogs',#要鏈接的數據庫實例的名稱,鏈接前須要已經完成建立;
        'USER': 'root',#MySQL數據庫的用戶名;
        'PASSWORD': 'Tqtl911!@%*)',#MySQL數據庫的密碼;
        'HOST': '47.95.121.154',#MySQL數據庫服務器的IP地址;
        'PORT': '3306'#MySQL數據庫的款口號,默認3306;
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_URL = '/static/'

AUTH_USER_MODEL = 'blog.UserInfo'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

四、進行數據庫遷移操做;

python manage.py makemigrations
python manage.py migrate

08-博客系統之登陸頁面設計

一、登陸頁面設計;

二、login.html設計之引入本地Bootstrap靜態文件;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>
<h3>登陸頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form action="">
                <div class="form-group">
                    <label for="user">用戶名</label>
                    <input type="text" id="user" class="form-control">
                </div>
                <div class="form-group">
                    <label for="pwd">密碼</label>
                    <input type="password" id="pwd" class="form-control">
                </div >
                <input type="button" class="btn btn-default pull-right login_btn" value="submit">
            </form>
        </div>
    </div>
</div>
</body>
</html>

三、views.py;

from django.shortcuts import render

# Create your views here.

def login(request):
    return render(request,"login.html")

四、settings.py之配置STATICFILE_DIRS目錄;

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static")
]

09-博客系統之驗證碼圖片的生成1

一、PIL圖像處理模塊初識;

  PIL:Python Imaging Library,已是Python平臺事實上的圖像處理標準庫了,PIL功能很是強大,且API很是簡單易用。php

  因爲PIL僅支持到Python 2.7,加上年久失修,因而一羣志願者在PIL的基礎上建立了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了許多新特性,所以,咱們能夠直接安裝使用Pillow。css

 pip install pillow

詳情請見:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014320027235877860c87af5544f25a8deeb55141d60c5000html

二、打開圖片的兩種方式;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

def login(request):
    return render(request,"login.html")


import random
def get_validCode_img(request):
    def get_random_color():
        return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
    #方式1-with open方法;
    # with open("lufei.jpg","rb") as f:
    #     data = f.read()

    #方式2;pip install pillow;
    from PIL import Image
    img = Image.new("RGB",(270,40),color=get_random_color())
    with open("validCode.png","wb") as f:
        img.save(f,"png")
    with open("validCode.png","rb") as f:
        data = f.read()
    return HttpResponse(data)

三、login.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>
<h3>登陸頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form action="">
                {% csrf_token %}
                <div class="form-group">
                    <label for="user">用戶名</label>
                    <input type="text" id="user" class="form-control">
                </div>
                <div class="form-group">
                    <label for="pwd">密碼</label>
                    <input type="password" id="pwd" class="form-control">
                </div >
                <div class="form-group">
                    <label for="pwd">驗證碼</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="valid_code form-control">
                        </div>
                        <div class="col-md-6"></div>
                        <img  width="260" height="45" src="/get_validCode_img/" alt="">
                    </div>
                </div>
                <input type="button" class="btn btn-default pull-right login_btn" value="submit">
            </form>
        </div>
    </div>
</div>
</body>
</html>

10-博客系統之驗證碼圖片的生成2

一、生成隨機字符串的兩種方法;

二、引入string、ImageDraw、ImageFont模塊;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

def login(request):
    return render(request,"login.html")


import random
def get_validCode_img(request):
    def get_random_color():
        return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
    #方式1-with open方法;
    # with open("lufei.jpg","rb") as f:
    #     data = f.read()

    #方式2;pip install pillow;
    # from PIL import Image
    # img = Image.new("RGB",(270,40),color=get_random_color())
    # with open("validCode.png","wb") as f:
    #     img.save(f,"png")
    # with open("validCode.png","rb") as f:
    #     data = f.read()

    #方式3:將數據放置於內存中,加快處理速度;
    # from PIL import Image
    # from io import BytesIO
    #
    # img = Image.new("RGB",(270,40),color=get_random_color())
    # f = BytesIO()
    # img.save(f,"png")
    # data = f.getvalue()

    #方式4:向圖像區域他添加噪點,和字符串;
    from PIL import Image,ImageDraw,ImageFont
    from io import BytesIO
    import random
    char = str(random.randint(0,9))

    img = Image.new("RGB",(270,40),color=get_random_color())
    draw = ImageDraw.Draw(img)
    kumo_font = ImageFont.truetype("static/font/kumo.ttf",size=28)

    #生成隨機字符串;
    #方法1:
    # for i in range(0,5):
    #     import string
    #     random_char = '  '.join(random.sample(string.ascii_lowercase  + string.ascii_uppercase,1))  # d4}5c+/m|97e@"16]s
    #     draw.text((i*50+20,5),random_char,get_random_color(),font=kumo_font)

    #方法2:
    for i in range(5):
        random_num = str(random.randint(0,9))
        random_lowercase = chr(random.randint(95,122))
        random_uppercase = chr(random.randint(65,90))
        random_char = random.choice([random_num,random_lowercase,random_uppercase])
        draw.text((i*50+20,5),random_char,get_random_color(),font=kumo_font)

    #進行畫圖
    #draw.line()
    #draw.point()
    f = BytesIO()
    img.save(f,"png")
    data = f.getvalue()

    return HttpResponse(data)

11-博客系統之驗證碼圖片的噪點燥線

一、添加噪點、燥線;

    #給圖片添加上噪點;
    width = 270
    height = 40
    for i in range(5):
        x1 = random.randint(0,width)
        x2 = random.randint(0,width)
        y1 = random.randint(0,height)
        y2 = random.randint(0,height)
        draw.line((x1,y1,x2,y2),fill=get_random_color())

    for i in range(10):
        draw.point([random.randint(0,width),random.randint(0,height)],fill=get_random_color())
        x = random.randint(0,width)
        y = random.randint(0,height)
        draw.arc((x,y,x+4,y+4),0,90,fill=get_random_color())

二、展現效果;

12-博客系統之驗證碼刷新

一、先引入jQuery文件;

二、添加鼠標點擊事件click();

三、給圖片添加一個id屬性,而後經過js代碼添加事件;

<script src="/static/blog/js/jquery-3.3.1.min.js"></script>
<script>
    //刷新圖片驗證碼;
    $("#valid_code_img").click(function () {
        $(this)[0].src+="?"
    })
</script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>
<h3>登陸頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form action="">
                {% csrf_token %}
                <div class="form-group">
                    <label for="user">用戶名</label>
                    <input type="text" id="user" class="form-control">
                </div>
                <div class="form-group">
                    <label for="pwd">密碼</label>
                    <input type="password" id="pwd" class="form-control">
                </div >
                <div class="form-group">
                    <label for="pwd">驗證碼</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="valid_code form-control">
                        </div>
                        <div class="col-md-6">
                        <img  width="260" height="45" id="valid_code_img" src="/get_validCode_img/" alt="">
              </div> </div> </div> <input type="button" class="btn btn-default pull-right login_btn" value="submit"> </form> </div> </div> </div> <script src="/static/blog/js/jquery-3.3.1.min.js"></script> <script> //刷新圖片驗證碼; $("#valid_code_img").click(function () { $(this)[0].src+="?" }) </script> </body> </html>

13-博客系統之保存驗證碼字符串

一、保存驗證字符串之Ajax引入;

二、views.py;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

from django.http import JsonResponse

def login(request):
    if request.method == "POST":
        response = {"user":None,"msg":None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code  = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        #print("valid_code_str",valid_code_str,type(valid_code_str))
        #print("valid_code",valid_code,type(valid_code))
        if valid_code.upper() == valid_code_str.upper():
            pass
        else:
            response["msg"] = "valid code error!"
        return JsonResponse(response)
    return render(request,"login.html")


import random
def get_validCode_img(request):
    def get_random_color():
        return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
    #方式1-with open方法;
    # with open("lufei.jpg","rb") as f:
    #     data = f.read()

    #方式2;pip install pillow;
    # from PIL import Image
    # img = Image.new("RGB",(270,40),color=get_random_color())
    # with open("validCode.png","wb") as f:
    #     img.save(f,"png")
    # with open("validCode.png","rb") as f:
    #     data = f.read()

    #方式3:將數據放置於內存中,加快處理速度;
    # from PIL import Image
    # from io import BytesIO
    #
    # img = Image.new("RGB",(270,40),color=get_random_color())
    # f = BytesIO()
    # img.save(f,"png")
    # data = f.getvalue()

    #方式4-向圖像區域他添加噪點,和字符串;
    from PIL import Image,ImageDraw,ImageFont
    from io import BytesIO
    import random
    char = str(random.randint(0,9))

    img = Image.new("RGB",(270,40),color=get_random_color())
    draw = ImageDraw.Draw(img)
    kumo_font = ImageFont.truetype("static/font/BASKVILL.TTF",size=28)

    #保存隨機字符串;
    valid_code_str = ""
    #生成隨機字符串;
    #方法1:
    for i in range(0,5):
        import string
        random_char = '  '.join(random.sample(string.ascii_lowercase  + string.ascii_uppercase,1))  # d4}5c+/m|97e@"16]s
        draw.text((i*50+20,5),random_char,get_random_color(),font=kumo_font)
        #保存驗證碼字符串;
        valid_code_str+= random_char

    #方法2:
    # for i in range(500):
    #     random_num = str(random.randint(0,9))
    #     random_lowercase = chr(random.randint(95,122))
    #     random_uppercase = chr(random.randint(65,90))
    #     random_char = random.choice([random_num,random_lowercase,random_uppercase])
    #     draw.text((i*50+20,5),random_char,get_random_color(),font=kumo_font)

    #進行畫圖;
    #draw.line()
    #draw.point()


    #給圖片添加上噪點;
    width = 270
    height = 40
    for i in range(5):
        x1 = random.randint(0,width)
        x2 = random.randint(0,width)
        y1 = random.randint(0,height)
        y2 = random.randint(0,height)
        draw.line((x1,y1,x2,y2),fill=get_random_color())

    for i in range(10):
        draw.point([random.randint(0,width),random.randint(0,height)],fill=get_random_color())
        x = random.randint(0,width)
        y = random.randint(0,height)
        draw.arc((x,y,x+4,y+4),0,90,fill=get_random_color())
    print("valid_code_str",valid_code_str)

    request.session["valid_code_str"] = valid_code_str
    '''
    一、生成隨機字符串;
    二、COOKIE{"sessionid":fdsfdsfds}
    三、django-session表生成記錄;
    '''
    f = BytesIO()
    img.save(f, "png")
    data = f.getvalue()
    return HttpResponse(data)

login.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>
<h3>登陸頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form >
                {% csrf_token %}
                <div class="form-group">
                    <label for="user">用戶名</label>
                    <input type="text" id="user" class="form-control">
                </div>
                <div class="form-group">
                    <label for="pwd">密碼</label>
                    <input type="password" id="pwd" class="form-control">
                </div >
                <div class="form-group">
                    <label for="pwd">驗證碼</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" id="valid_code">
                        </div>
                        <div class="col-md-6">
                            <img  width="260" height="45" id="valid_code_img" src="/get_validCode_img/" alt="">
                        </div>
                    </div>
                </div>
                <input type="button" class="btn btn-default pull-right login_btn" value="submit">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>
<script>
    //刷新圖片驗證碼;
    $("#valid_code_img").click(function () {
        $(this)[0].src+="?"
    });

    //登錄過驗證;
    $(".login_btn").click(function () {
        $.ajax({
            url:"",
            type:"post",
            data:{
                user:$("#user").val(),
                pwd:$("#pwd").val(),
                valid_code:$("#valid_code").val(),
                csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),

            },
            success:function (data) {
                console.log(data)

            }
        })
    })


</script>


</body>
</html>

14-博客系統之登陸驗證

一、修改消息提示語;

15-博客系統之登陸驗證代碼優化

一、新增utils目錄,將功能遷移至此;

views.py;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth

def login(request):
    if request.method == "POST":
        response = {"user":None,"msg":None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code  = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        #print("valid_code_str",valid_code_str,type(valid_code_str))
        #print("valid_code",valid_code,type(valid_code))
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username = user,password = pwd)
            if user:
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request,"login.html")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def index(request):
    return render(request,"index.html")

"""
小結:
一、一次請求伴隨着屢次請求;
二、PIL模塊的掌握;
三、session存儲;
四、驗證碼刷新,基於js鼠標的click()事件進行;
"""

validCode.py;

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:2018/8/23 21:30

import random

def get_random_color():
    return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))


def get_valid_code_img(request):
    # 方式1-with open方法;
    # with open("lufei.jpg","rb") as f:
    #     data = f.read()

    # 方式2;pip install pillow;
    # from PIL import Image
    # img = Image.new("RGB",(270,40),color=get_random_color())
    # with open("validCode.png","wb") as f:
    #     img.save(f,"png")
    # with open("validCode.png","rb") as f:
    #     data = f.read()

    # 方式3:將數據放置於內存中,加快處理速度;
    # from PIL import Image
    # from io import BytesIO
    #
    # img = Image.new("RGB",(270,40),color=get_random_color())
    # f = BytesIO()
    # img.save(f,"png")
    # data = f.getvalue()

    # 方式4-向圖像區域他添加噪點,和字符串;
    from PIL import Image, ImageDraw, ImageFont
    from io import BytesIO
    import random
    char = str(random.randint(0, 9))

    img = Image.new("RGB", (270, 40), color=get_random_color())
    draw = ImageDraw.Draw(img)
    kumo_font = ImageFont.truetype("static/font/BASKVILL.TTF", size=28)

    # 保存隨機字符串;
    valid_code_str = ""
    # 生成隨機字符串;
    # 方法1:
    for i in range(0, 5):
        import string
        random_char = '  '.join(
            random.sample(string.ascii_lowercase + string.ascii_uppercase, 1))  # d4}5c+/m|97e@"16]s
        draw.text((i * 50 + 20, 5), random_char, get_random_color(), font=kumo_font)
        # 保存驗證碼字符串;
        valid_code_str += random_char

    # 方法2:
    # for i in range(500):
    #     random_num = str(random.randint(0,9))
    #     random_lowercase = chr(random.randint(95,122))
    #     random_uppercase = chr(random.randint(65,90))
    #     random_char = random.choice([random_num,random_lowercase,random_uppercase])
    #     draw.text((i*50+20,5),random_char,get_random_color(),font=kumo_font)

    # 進行畫圖;
    # draw.line()
    # draw.point()

    # 給圖片添加上噪點;
    width = 270
    height = 40
    for i in range(5):
        x1 = random.randint(0, width)
        x2 = random.randint(0, width)
        y1 = random.randint(0, height)
        y2 = random.randint(0, height)
        draw.line((x1, y1, x2, y2), fill=get_random_color())

    for i in range(10):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
    print("valid_code_str", valid_code_str)

    request.session["valid_code_str"] = valid_code_str
    '''
    一、生成隨機字符串;
    二、COOKIE{"sessionid":fdsfdsfds};
    三、django-session表生成記錄;
    '''
    f = BytesIO()
    img.save(f, "png")
    data = f.getvalue()
    return data

二、新增圖片驗證碼1秒刷新功能,基於js的setTimeout()方法實現;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>
<h3>登陸頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form >
                {% csrf_token %}
                <div class="form-group">
                    <label for="user">用戶名</label>
                    <input type="text" id="user" class="form-control">
                </div>
                <div class="form-group">
                    <label for="pwd">密碼</label>
                    <input type="password" id="pwd" class="form-control">
                </div >
                <div class="form-group">
                    <label for="pwd">驗證碼</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" id="valid_code">
                        </div>
                        <div class="col-md-6">
                            <img  width="260" height="45" id="valid_code_img" src="/get_validCode_img/" alt="">
                        </div>
                    </div>
                </div>
                <input type="button" class="btn btn-default login_btn" value="submit"><span class="error"></span>
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>
<script>
    //刷新圖片驗證碼;
    $("#valid_code_img").click(function () {
        $(this)[0].src+="?"
    });

    //登錄過驗證;
    $(".login_btn").click(function () {
        $.ajax({
            url:"",
            type:"post",
            data:{
                user:$("#user").val(),
                pwd:$("#pwd").val(),
                valid_code:$("#valid_code").val(),
                csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),

            },
            success:function (data) {
                console.log(data);
                if (data.user){
                    location.href = "/index/"
                }else {
                    $(".error").text(data.msg).css({"color":"red","margin-left":"10px"});
                    //清空錯誤消息提示,1000毫秒;
                    setTimeout(function () {
                        $(".error").text("")
                    },1000)
                }
            }
        })
    });


</script>


</body>
</html>

16-博客系統之滑動驗證碼做業

極驗官網:http://www.geetest.com/前端

17-博客系統之基於form組件的註冊頁面設計1

一、註冊頁面的路由配置urls.py;

"""cnblogs URL Configuration

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

from blog import views
urlpatterns = {
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),
}

二、註冊頁面的views.py視圖函數編寫;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth

def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user":None,"msg":None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code  = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username = user,password = pwd)
            if user:
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request,"login.html")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    return render(request,"index.html")


from django import forms
from django.forms import widgets

class UserForm(forms.Form):
    user = forms.CharField(max_length=32,label="用戶名",widget=widgets.TextInput(attrs={"class":"form-control"}))
    pwd = forms.CharField(max_length=32,label="密碼",widget=widgets.PasswordInput(attrs={"class":"form-control"}))
    r_pwd = forms.CharField(max_length=32,label="確認密碼",widget=widgets.PasswordInput(attrs={"class":"form-control"}))
    email = forms.EmailField(max_length=32,label="註冊郵箱",widget=widgets.EmailInput(attrs={"class":"form-control"}))

def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    form = UserForm()
    return render(request,"register.html",{"form":form})

三、註冊頁面的模板templates下的register.html編寫(基於forms組件循環生成並添加約束信息);

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form >
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="user">{{ field.label }}</label>
                        {{ field }}
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">頭像</label>
                    <input type="file">
                </div>

                <input type="button" class="btn btn-default login_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

</body>
</html>

18-博客系統之註冊頁面的默認頭像

一、點擊頭像至關於點擊input標籤的功能實現;

  • 1)將label標籤包含img標籤;
  • 2)將label標籤的for值等同於input標籤的id值;
  • 3)爲input標籤設置display:none的隱藏屬性;

二、register.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{
            display: none;
        }
        #avatar_img{
            margin-left: 20px;
        }
    </style>
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form >
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }}
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">
                        頭像
                        <img id="avatar_img" width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar" >
                </div>
                <input type="button" class="btn btn-default login_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

</body>
</html>

19-博客系統之註冊頁面的頭像預覽功能

一、頭像預覽功能實現的js代碼;

二、獲取上傳後文件的方法;

  • $("#avatar")[0].files[0],獲得以下內容:File(11414) {name: "keep.jpg", lastModified: 1531732278496, lastModifiedDate: Mon Jul 16 2018 17:11:18 GMT+0800 (中國標準時間), webkitRelativePath: "", size: 11414, …}
<script>
    $("#avatar").change(function () {
        //一、獲取用戶選中的文件對象;
        var file_obj = $(this)[0].files[0];
        //二、獲取文件對象的路徑;
        var reader =  new FileReader();
        reader.readAsDataURL(file_obj);
       //三、修改img的src屬性值,src= 文件對象的路徑;
        reader.onload = function(){
            $("#avatar_img").attr("src",reader.result)
        };

    })
</script>

20-博客系統之基於Ajax的form data數據

一、經過Ajax方法實現向後端傳送數據;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{
            display: none;
        }
        #avatar_img{
            margin-left: 20px;
        }
    </style>
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form >
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }}
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">
                        頭像
                        <img id="avatar_img" width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar" >
                </div>
                <input type="button" class="btn btn-default reg_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

<!--編寫js代碼-->
<script>
    $("#avatar").change(function () {
        //一、獲取用戶選中的文件對象;
        var file_obj = $(this)[0].files[0];
        //二、獲取文件對象的路徑;
        var reader =  new FileReader();
        reader.readAsDataURL(file_obj);
       //三、修改img的src屬性值,src= 文件對象的路徑;
        reader.onload = function(){
            $("#avatar_img").attr("src",reader.result)
        };

    });
    //基於Ajax提交事件;
    $(".reg_btn").click(function () {
        var formdata = new FormData();
        formdata.append("user",$("#id_user").val());
        formdata.append("pwd",$("#id_pwd").val());
        formdata.append("r_pwd",$("#id_r_pwd").val());
        formdata.append("email",$("#id_email").val());
        formdata.append("avatar",$("#avatar")[0].files[0]);
        formdata.append("csrfmiddlewaretoken",$("[name = 'csrfmiddlewaretoken']").val());

        $.ajax({
            url:"",
            type:"post",
            contentType:false,
            processData:false,
            data:formdata,
            success:function (data) {
                console.log(data)

            }
        })
    })
</script>

</body>
</html>

二、views.py進行邏輯判斷;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth

def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user":None,"msg":None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code  = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username = user,password = pwd)
            if user:
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request,"login.html")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    return render(request,"index.html")


from django import forms
from django.forms import widgets
from django.http import JsonResponse

class UserForm(forms.Form):
    user = forms.CharField(max_length=32,label="用戶名",widget=widgets.TextInput(attrs={"class":"form-control"}))
    pwd = forms.CharField(max_length=32,label="密碼",widget=widgets.PasswordInput(attrs={"class":"form-control"}))
    r_pwd = forms.CharField(max_length=32,label="確認密碼",widget=widgets.PasswordInput(attrs={"class":"form-control"}))
    email = forms.EmailField(max_length=32,label="註冊郵箱",widget=widgets.EmailInput(attrs={"class":"form-control"}))

def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    #if request.method == "POST":
    if request.is_ajax():
        print(request.POST)
        form = UserForm(request.POST)


        response = {"user":None,"msg":None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
        else:
            print(form.cleaned_data)
            print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request,"register.html",{"form":form})

21-博客系統之基於Ajax提交from data的數據的優化

一、使用serializeArray()方法進行優化;

注意犯的錯誤,Js中的代碼多行註釋的方法爲:/*被註釋的內容,而不是<!--被註釋的內容-->*/

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{
            display: none;
        }
        #avatar_img{
            margin-left: 20px;
        }
    </style>
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form id="form">
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }}
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">
                        頭像
                        <img id="avatar_img" width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar" >
                </div>
                <input type="button" class="btn btn-default reg_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

<!--編寫js代碼-->
<script>
    $("#avatar").change(function () {
        //一、獲取用戶選中的文件對象;
        var file_obj = $(this)[0].files[0];
        //二、獲取文件對象的路徑;
        var reader =  new FileReader();
        reader.readAsDataURL(file_obj);
        //三、修改img的src屬性值,src= 文件對象的路徑;
        reader.onload = function(){
            $("#avatar_img").attr("src",reader.result)
        };

    });
    //基於Ajax提交事件;
    $(".reg_btn").click(function () {

        var formdata = new FormData();
        console.log($("#form").serializeArray());
        var request_data = $("#form").serializeArray();
        $.each(request_data,function (index,data) {
            formdata.append(data.name,data.value)
        });
        formdata.append("avatar",$("#avatar")[0].files[0]);

        /* var formdata = new FormData();
         formdata.append("user",$("#id_user").val());
         formdata.append("pwd",$("#id_pwd").val());
         formdata.append("r_pwd",$("#id_r_pwd").val());
         formdata.append("email",$("#id_email").val());
         formdata.append("avatar",$("#avatar")[0].files[0]);
         formdata.append("csrfmiddlewaretoken",$("[name = 'csrfmiddlewaretoken']").val());*/

        $.ajax({
            url:"",
            type:"post",
            contentType:false,
            processData:false,
            data:formdata,
            success:function (data) {
                console.log(data)

            }
        })
    })
</script>

</body>
</html>

22-博客系統之基於Ajax在註冊頁面顯示錯誤消息1

一、基於Ajax實現頁面錯誤消息;

register.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{
            display: none;
        }
        #avatar_img{
            margin-left: 20px;
        }
        .error{
            color: red;
        }
    </style>
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form id="form">
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }}<span class="error pull-right"></span>
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">
                        頭像
                        <img id="avatar_img" width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar" name="avatar">
                </div>
                <input type="button" class="btn btn-default reg_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

<!--編寫js代碼-->
<script>
    $("#avatar").change(function () {
        //一、獲取用戶選中的文件對象;
        var file_obj = $(this)[0].files[0];
        //二、獲取文件對象的路徑;
        var reader =  new FileReader();
        reader.readAsDataURL(file_obj);
        //三、修改img的src屬性值,src= 文件對象的路徑;
        reader.onload = function(){
            $("#avatar_img").attr("src",reader.result)
        };

    });
    //基於Ajax提交事件;
    $(".reg_btn").click(function () {

        var formdata = new FormData();
        console.log($("#form").serializeArray());
        var request_data = $("#form").serializeArray();
        $.each(request_data,function (index,data) {
            formdata.append(data.name,data.value)
        });
        formdata.append("avatar",$("#avatar")[0].files[0]);

       /* var formdata = new FormData();
         formdata.append("user",$("#id_user").val());
         formdata.append("pwd",$("#id_pwd").val());
         formdata.append("r_pwd",$("#id_r_pwd").val());
         formdata.append("email",$("#id_email").val());
         formdata.append("avatar",$("#avatar")[0].files[0]);
         formdata.append("csrfmiddlewaretoken",$("[name = 'csrfmiddlewaretoken']").val());*/

        $.ajax({
            url:"",
            type:"post",
            contentType:false,
            processData:false,
            data:formdata,
            success:function (data) {
                console.log(data);
                if(data.user){
                    //註冊成功;
                }else {
                    //console.log(data.msg)
                    $.each(data.msg,function (field,error_list) {
                        console.log(field,error_list);
                        $("#id_"+field).next().html(error_list[0])
                    })
                }
            }
        });
    });
</script>

</body>
</html>

23-博客系統之基於Ajax在註冊頁面顯示錯誤消息2

一、addClass以及removeClass以及Bootstrap中has-error的使用;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{
            display: none;
        }
        #avatar_img{
            margin-left: 20px;
        }
        .error{
            color: red;
        }
    </style>
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form id="form">
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }}<span class="error pull-right"></span>
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">
                        頭像
                        <img id="avatar_img" width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar" name="avatar">
                </div>
                <input type="button" class="btn btn-default reg_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

<!--編寫js代碼-->
<script>
    $("#avatar").change(function () {
        //一、獲取用戶選中的文件對象;
        var file_obj = $(this)[0].files[0];
        //二、獲取文件對象的路徑;
        var reader =  new FileReader();
        reader.readAsDataURL(file_obj);
        //三、修改img的src屬性值,src= 文件對象的路徑;
        reader.onload = function(){
            $("#avatar_img").attr("src",reader.result)
        };

    });
    //基於Ajax提交事件;
    $(".reg_btn").click(function () {

        var formdata = new FormData();
        console.log($("#form").serializeArray());
        var request_data = $("#form").serializeArray();
        $.each(request_data,function (index,data) {
            formdata.append(data.name,data.value)
        });
        formdata.append("avatar",$("#avatar")[0].files[0]);

        /* var formdata = new FormData();
          formdata.append("user",$("#id_user").val());
          formdata.append("pwd",$("#id_pwd").val());
          formdata.append("r_pwd",$("#id_r_pwd").val());
          formdata.append("email",$("#id_email").val());
          formdata.append("avatar",$("#avatar")[0].files[0]);
          formdata.append("csrfmiddlewaretoken",$("[name = 'csrfmiddlewaretoken']").val());*/

        $.ajax({
            url:"",
            type:"post",
            contentType:false,
            processData:false,
            data:formdata,
            success:function (data) {
                console.log(data);
                if(data.user){
                    //註冊成功;
                }else {//註冊失敗
                    //console.log(data.msg)
                    //清空錯誤提示消息;
                    $("span.error").html();
                    $(".form-group").removeClass("has-error");
                    //展現這次提提交的信息;
                    $.each(data.msg,function (field,error_list) {
                        console.log(field,error_list);
                        $("#id_"+field).next().html(error_list[0]);
                        $("#id_"+field).parent().addClass("has-error");
                    })
                }
            }
        });
    });
</script>

</body>
</html>

24-博客系統之form組件的局部鉤子與全局鉤子的應用

一、form組件中的鉤子和全局鉤子應用;

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# __Author__:TQTL911
# Version:python3.6.6
# Time:2018/8/24 14:41
from django import forms
from django.forms import widgets
from django.http import JsonResponse
from blog.models import UserInfo
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError

class UserForm(forms.Form):
    user = forms.CharField(max_length=32,error_messages={"required":"該字段不能爲空!"},label="用戶名",widget=widgets.TextInput(attrs={"class":"form-control"}))
    pwd = forms.CharField(max_length=32,label="密碼",widget=widgets.PasswordInput(attrs={"class":"form-control"}))
    r_pwd = forms.CharField(max_length=32,label="確認密碼",widget=widgets.PasswordInput(attrs={"class":"form-control"}))
    email = forms.EmailField(max_length=32,label="註冊郵箱",widget=widgets.EmailInput(attrs={"class":"form-control"}))

    def clean_user(self):
        user = self.cleaned_data.get("user")
        user = UserInfo.objects.filter(username=user).first()

        if not user:
            return user
        else:
            raise ValidationError("該用戶已經註冊")
    def clean(self):
        pwd = self.cleaned_data.get("pwd")
        r_pwd = self.cleaned_data.get("r_pwd")

        if pwd == r_pwd:
            return self.cleaned_data
        else:
            raise ValidationError("兩次密碼不一致!")

二、from django.core.exceptions import NON_FIELD_ERRORS, ValidationError的引入;

三、拋出中文異常的方法;

四、cleaned_data的用法;

register.html;

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊頁面</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar{
            display: none;
        }
        #avatar_img{
            margin-left: 20px;
        }
        .error{
            color: red;
        }
    </style>
</head>
<body>
<h3>註冊頁面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form id="form">
                {% csrf_token %}
                <!--進行渲染form對象-->
                {% for field in form %}
                    <div class="form-group">
                        <label for="{{ field.auto_id }}">{{ field.label }}</label>
                        {{ field }}<span class="error pull-right"></span>
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="avatar">
                        頭像
                        <img id="avatar_img" width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar" name="avatar">
                </div>
                <input type="button" class="btn btn-default reg_btn" value="提交">
            </form>
        </div>
    </div>
</div>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>

<!--編寫js代碼-->
<script>
    $("#avatar").change(function () {
        //一、獲取用戶選中的文件對象;
        var file_obj = $(this)[0].files[0];
        //二、獲取文件對象的路徑;
        var reader =  new FileReader();
        reader.readAsDataURL(file_obj);
        //三、修改img的src屬性值,src= 文件對象的路徑;
        reader.onload = function(){
            $("#avatar_img").attr("src",reader.result)
        };

    });
    //基於Ajax提交事件;
    $(".reg_btn").click(function () {

        var formdata = new FormData();
        console.log($("#form").serializeArray());
        var request_data = $("#form").serializeArray();
        $.each(request_data,function (index,data) {
            formdata.append(data.name,data.value)
        });
        formdata.append("avatar",$("#avatar")[0].files[0]);

        /* var formdata = new FormData();
          formdata.append("user",$("#id_user").val());
          formdata.append("pwd",$("#id_pwd").val());
          formdata.append("r_pwd",$("#id_r_pwd").val());
          formdata.append("email",$("#id_email").val());
          formdata.append("avatar",$("#avatar")[0].files[0]);
          formdata.append("csrfmiddlewaretoken",$("[name = 'csrfmiddlewaretoken']").val());*/

        $.ajax({
            url:"",
            type:"post",
            contentType:false,
            processData:false,
            data:formdata,
            success:function (data) {
                console.log(data);
                if(data.user){
                    //註冊成功;
                }else {//註冊失敗
                    //console.log(data.msg)
                    //清空錯誤提示消息;
                    $("span.error").html();
                    $(".form-group").removeClass("has-error");
                    //展現這次提提交的信息;
                    $.each(data.msg,function (field,error_list) {
                        console.log(field,error_list);
                        if(field=="__all__"){
                            $("#id_r_pwd").next().html(error_list[0]).parent().addClass("has-error")
                        }
                        $("#id_"+field).next().html(error_list[0]);
                        $("#id_"+field).parent().addClass("has-error");
                    })
                }
            }
        });
    });
</script>

</body>
</html>

25-博客系統之FileFiled字段

一、先導入from blog.models import UserInfo;

二、is_valid()校驗經過後,向數據庫庫中寫入數據,注意此時使用的是,UserInfo.objects.create_user()方法進行寫入數據;

三、進行註冊功能的驗證;

四、進行登陸驗證;

 

 

 

 

 

26-博客系統之media配置1

一、settings.py中,STATICFILES_DIRS、MEDIA_ROOT配置;

二、上傳文件,default的邏輯判斷;

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth

def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user":None,"msg":None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code  = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username = user,password = pwd)
            if user:
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request,"login.html")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    return render(request,"index.html")


from blog.Myforms import UserForm
from blog.models import UserInfo
def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    #if request.method == "POST":
    if request.is_ajax():
        print(request.POST)
        form = UserForm(request.POST)

        response = {"user":None,"msg":None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            #生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)

        else:
            print(form.cleaned_data)
            print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request,"register.html",{"form":form})

27-博客系統之media配置2

一、settings.py中MEDIAZ_URL的配置;

二、urls.py中MEDIA_ROOT的引用而不是MEDIA_URL;

28-博客系統之生成用戶對象的代碼優化

一、減小冗餘代碼,提升可讀性;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    return render(request, "index.html")


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}
            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, )


        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})

二、import使用方式,通常位於py文件的頂部且有順序,先xx後xx;

Pycharm中,使用Ctrl+Shift+L組合鍵,進行Reformat Code操做,提高代碼排版規範;

三、遵循PEP8代碼編寫規範,提升代碼質量;

Python語言規範;https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_language_rules/

29-博客系統之系統首頁的導航區域

一、Bootstrap之導航條的使用;

二、{{ request.user.username }}的使用;

三、auth.logout(request) # 等同於request.session.flush();

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客系統首頁</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <style>
        #user_icon {
            font-size: 18px;
            margin-right: 10px;
            vertical-align: -3px;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">博客園</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">隨筆 <span class="sr-only">(current)</span></a></li>
                <li><a href="#">新聞</a></li>
                <li><a href="#">博文</a></li>
            </ul>

            <ul class="nav navbar-nav navbar-right">
                {% if request.user.is_authenticated %}
                    <li><a href="#"><span id="user_icon" class="glyphicon glyphicon-user"></span>{{ request.user.username }}</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                           aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">修改密碼</a></li>
                            <li><a href="#">修改頭像</a></li>
                            <li><a href="/logout/">註銷</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                        </ul>
                    </li>

                {% else %}
                    <li><a href="/login/">登陸</a></li>
                    <li><a href="/register/">註冊</a></li>
                {% endif %}

            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>

</body>
</html>

views.py;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    return render(request, "index.html")


def logout(request):
    auth.logout(request)  # 等同於request.session.flush()
    return redirect("/login/")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}

            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})

urls.py;

"""cnblogs URL Configuration

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    re_path('^$', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),
    # media配置;
    re_path(r"media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT}),
]

30-博客系統之系統首頁的主體佈局

一、基於Bootstrap的格柵系統,定製頁面佈局;

<!--引入BootStrap格柵系統-->
<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-info">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
        <div class="col-md-6">222</div>
        <div class="col-md-3">
            <div class="panel panel-default">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-default">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
    </div>
</div>

31-博客系統之admin的簡單實用

一、Django下的admin初識;

Django內部的一個組件:後臺數據管理組件(Web界面);

建立超級用戶的方法:python manage.py createsuperuser 針對用戶認證,在blog_userinfo表中生成記錄,is_super字段值爲1;

二、settings.py中的admin說明;

三、基於應用名稱的blog中的admin.py進行表的註冊;

 

from django.contrib import admin

# Register your models here.
from blog import models

admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Category)
admin.site.register(models.Tag)
admin.site.register(models.Article)
admin.site.register(models.ArticleUpDown)
admin.site.register(models.Article2Tag)
admin.site.register(models.Comment)

 

 

 

32-博客系統之基於admin錄入文章數據

一、經過Web前端頁面進行文章數據的錄入;

33-博客系統之系統首頁的文章列表的渲染1

一、文章列表的渲染展現;

<div class="col-md-6">
            <div class="article_list">
                {% for articel in article_list %}
                    <div class="articel-item">
                        <h5><a href="">{{ articel.title }}</a></h5>
                        <div class="article-desc">
                        <span class="media-left">
                            <a href=""><img width="56" height="56" src="media/{{ articel.user.avatar }}" alt=""></a>
                        </span>
                            <span class="media-right">
                            {{ articel.desc }}
                        </span>
                        </div>
                        <hr>
                    </div>
                {% endfor %}
            </div>
        </div>

 

34-博客系統之系統首頁的文章列表的渲染2

一、首頁文章列表渲染;

index.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客系統首頁</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <style>
        #user_icon {
            font-size: 18px;
            margin-right: 10px;
            vertical-align: -3px;
        }
        .pub_info{
            margin-top: 10px;
        }
        .pub_info .glyphicon-comment{
            vertical-align: -1px;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-default">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">博客園</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active"><a href="#">隨筆 <span class="sr-only">(current)</span></a></li>
                <li><a href="#">新聞</a></li>
                <li><a href="#">博文</a></li>
            </ul>

            <ul class="nav navbar-nav navbar-right">
                {% if request.user.is_authenticated %}
                    <li><a href="#"><span id="user_icon"
                                          class="glyphicon glyphicon-user"></span>{{ request.user.username }}</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                           aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">修改密碼</a></li>
                            <li><a href="#">修改頭像</a></li>
                            <li><a href="/logout/">註銷</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                        </ul>
                    </li>

                {% else %}
                    <li><a href="/login/">登陸</a></li>
                    <li><a href="/register/">註冊</a></li>
                {% endif %}

            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>

<!--引入BootStrap格柵系統-->
<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-info">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="article_list">
                {% for articel in article_list %}
                    <div class="articel-item">
                        <h5><a href="">{{ articel.title }}</a></h5>
                        <div class="article-desc">
                        <span class="media-left">
                            <a href=""><img width="56" height="56" src="media/{{ articel.user.avatar }}" alt=""></a>
                        </span>
                            <span class="media-right">
                            {{ articel.desc }}
                        </span>
                        </div>
                        <hr>
                    </div>
                    <div class="small pub_info">
                    <span><a href="">{{ articel.user.username }}</a></span>&nbsp;&nbsp;&nbsp;
                    <span>發佈於&nbsp;&nbsp;{{ articel.create_time|date:"Y-m-d H:i" }}</span>
                    <span class="glyphicon glyphicon-comment"></span>評論({{ articel.comment_count }})
                    <span class="glyphicon glyphicon-thumbs-up"></span>點贊({{ articel.up_count }})
                    </div>
                {% endfor %}
            </div>
        </div>
        <div class="col-md-3">
            <div class="panel panel-default">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-default">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

35-博客系統之我的站點的頁面文章的查詢

一、urls.py新增我的站點home_site訪問路徑;

"""cnblogs URL Configuration

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    re_path('^$', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),
    # media配置;
    re_path(r'media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
    # 我的站點URL;
    re_path(r'^(?P<username>\w+)$', views.home_site),
]

二、views.py;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo
from blog import models


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    article_list = models.Article.objects.all()

    return render(request, "index.html", {"article_list": article_list})


def logout(request):
    auth.logout(request)  # 等同於request.session.flush()
    return redirect("/login/")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}

            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})


def home_site(request, username):
    """
    我的站點視圖函數;
    :param request:
    :return:
    """
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在;
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象:
    blog = user.blog
    # 當前用戶或者當前站點對應的全部文章;
    # 基於對象查詢;
    # article_list = user.article_set.all()
    # 基於雙下劃線的查詢;
    article_list = models.Article.objects.filter(user=user)
    return render(request, "home_site.html")

36-博客系統之我的站點頁面的標籤與分類查詢

一、標籤以及分類的查詢方法;

def home_site(request, username):
    """
    我的站點視圖函數;
    :param request:
    :return:
    """
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在;
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象:
    blog = user.blog
    # 當前用戶或者當前站點對應的全部文章;
    # 基於對象查詢;
    # article_list = user.article_set.all()
    # 基於雙下劃線的查詢;
    article_list = models.Article.objects.filter(user=user)

    # 每個後表的模型.objedts.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 一、查詢每個分類名稱以及對應的文章數;
    ret = models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title", "c")
    print(ret)
    # 二、查詢當前站點的每個分類名稱以及對應的文章數;
    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 三、查詢當前站點的每個標籤名稱對應的文章數;
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)

    return render(request, "home_site.html")

37-博客系統之我的站點頁面的日期查詢1

一、SQL查詢語句,針對於顯示的格式化方法:data_format;

 

38-博客系統之我的站點頁面的日期查詢2

一、日期查詢之extra()函數;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo
from blog import models
from django.db.models import Count


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    article_list = models.Article.objects.all()

    return render(request, "index.html", {"article_list": article_list})


def logout(request):
    auth.logout(request)  # 等同於request.session.flush()
    return redirect("/login/")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}

            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})


def home_site(request, username):
    """
    我的站點視圖函數;
    :param request:
    :return:
    """
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在;
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象:
    blog = user.blog
    # 當前用戶或者當前站點對應的全部文章;
    # 基於對象查詢;
    # article_list = user.article_set.all()
    # 基於雙下劃線的查詢;
    article_list = models.Article.objects.filter(user=user)

    # 每個後表的模型.objedts.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 一、查詢每個分類名稱以及對應的文章數;
    ret1 = models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title", "c")
    print(ret1)
    # 二、查詢當前站點的每個分類名稱以及對應的文章數;
    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 三、查詢當前站點的每個標籤名稱對應的文章數;
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)
    #四、查詢當前站點每個年月的名稱以及對應的文章數之extra函數;
    ret2 = models.Article.objects.extra(select={"is_recent":"create_time > '2018-08-26'"}).values("title","is_recent")
    print(ret2)
    ret3 = models.Article.objects.extra(select={"y_m_d_date":"date_format(create_time,'%%Y-%%m-%%d')"}).values("title","y_m_d_date")
    print("這裏是ret3",ret3)
    return render(request, "home_site.html")

39-博客系統之我的站點頁面的日期查詢3

一、以年和月的格式顯示;

date_list = models.Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(c = Count("nid")).values("y_m_date","c")
    print("這裏是date_list",date_list)

40-博客系統之我的站點頁面的日期查詢4

一、使用Django內置的TruncMonth代理extra()方法以及date_format;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo
from blog import models
from django.db.models import Count


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    article_list = models.Article.objects.all()

    return render(request, "index.html", {"article_list": article_list})


def logout(request):
    auth.logout(request)  # 等同於request.session.flush()
    return redirect("/login/")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}

            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})


def home_site(request, username):
    """
    我的站點視圖函數;
    :param request:
    :return:
    """
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在;
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象:
    blog = user.blog
    # 當前用戶或者當前站點對應的全部文章;
    # 基於對象查詢;
    # article_list = user.article_set.all()
    # 基於雙下劃線的查詢;
    article_list = models.Article.objects.filter(user=user)

    # 每個後表的模型.objedts.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 一、查詢每個分類名稱以及對應的文章數;
    ret1 = models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title", "c")
    print(ret1)
    # 二、查詢當前站點的每個分類名稱以及對應的文章數;
    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 三、查詢當前站點的每個標籤名稱對應的文章數;
    """
    方式1:
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)
    #四、查詢當前站點每個年月的名稱以及對應的文章數之extra函數;
    ret2 = models.Article.objects.extra(select={"is_recent":"create_time > '2018-08-26'"}).values("title","is_recent")
    print(ret2)
    date_list = models.Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(c = Count("nid")).values("y_m_date","c")
    print("這裏是date_list",date_list)
    """

    """
    方式2:
    """
    from django.db.models.functions import TruncMonth
    ret4 = models.Article.objects.filter(user=user).annotate(month = TruncMonth("Create_time")).values("month").annotate(c= Count("nid")).values_list("month","c")
    print("ret----->",ret4)

    return render(request, "home_site.html")

41-博客系統之我的站點頁面的渲染布局1

一、頂部導航欄設置,右浮動設置;

二、基於博客的title向頁面渲染數據;

home_site.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home_site</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            width: 100%;
            height: 60px;
            background-color: #369;
        }

        .header .title {
            font-size: 18px;
            font-weight: 100;
            line-height: 60px;
            color: white;
            margin-left: 15px;
            margin-top: -10px;

        }
        .backend{
            float: right;
            color: white;
            text-decoration: none;
            font-size: 14px;
            margin-right: 10px;
            margin-top: 10px;
        }
    </style>
</head>
<body>
<div class="header">
    <div class="content">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="" class="backend">管理</a>
        </p>
    </div>
</div>
</body>
</html>

42-博客系統之我的站點頁面的渲染布局2

一、站點頁面的格柵系統佈局渲染;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home_site</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            width: 100%;
            height: 60px;
            background-color: #369;
        }

        .header .title {
            font-size: 18px;
            font-weight: 100;
            line-height: 60px;
            color: white;
            margin-left: 15px;
            margin-top: -10px;

        }

        .backend {
            float: right;
            color: white;
            text-decoration: none;
            font-size: 14px;
            margin-right: 10px;
            margin-top: 10px;
        }

        .pub_info {
            margin-top: 10px;
            color: darkgray;
        }

    </style>
</head>
<body>
<div class="header">
    <div class="content">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="" class="backend">管理</a>
        </p>
    </div>
</div>
<div class="container">
    <div class="row">
        <div class="col-md-3">

        </div>
        <div class="col-md-9">
            <div class="article_list">
                {% for article in article_list %}
                    <div class="article-item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div class="article-desc">
                            {{ article.desc }}
                        </div>
                    </div>
                    <div class="small pub_info pull-right">
                        <span>發佈於&nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>
                        <span class="glyphicon glyphicon-comment"></span>評論({{ article.comment_count }})
                        <span class="glyphicon glyphicon-thumbs-up"></span>點贊({{ article.up_count }})
                    </div>
                    <hr>
                {% endfor %}
            </div>
        </div>
    </div>
</div>
</body>
</html>

43-博客系統之我的站點頁面的渲染布局3

一、在Bootstrap的柵格系統col-md-3左側欄設置「個人標籤」、「隨筆分類」、「隨筆歸檔」等分類tag;

<div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">個人標籤</div>
                <div class="panel-body">
                    {% for tag in tag_list %}
                        <p>{{ tag.0 }}({{ tag.1 }})</p>
                    {% endfor %}

                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">隨筆分類</div>
                <div class="panel-body">
                    {% for cate in cate_list %}
                        <p>{{ cate.0 }}({{ cate.1 }})</p>
                    {% endfor %}

                </div>
            </div>
            <div class="panel panel-success">
                <div class="panel-heading">隨筆歸檔</div>
                <div class="panel-body">
                    {% for date in date_list %}
                        <p>{{ date.0 }}({{ date.1 }})</p>
                    {% endfor %}

                </div>
            </div>

        </div>

二、經過數據庫進行渲染的到數據並循環進行前端展現;

views.py;

def home_site(request, username, **kwargs):
    """
    我的站點視圖函數
    :param request:
    :return:
    """

    print("kwargs", kwargs)  # 區分訪問是的站點頁面仍是站點下的跳轉頁面
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查詢當前站點對象

    blog = user.blog

    # 1 當前用戶或者當前站點對應全部文章
    # 基於對象查詢
    # article_list=user.article_set.all()
    # 基於 __

    article_list = models.Article.objects.filter(user=user)

    if kwargs:
        condition = kwargs.get("condition")
        param = kwargs.get("param")  # 2012-12

        if condition == "category":
            article_list = article_list.filter(category__title=param)
        elif condition == "tag":
            article_list = article_list.filter(tags__title=param)
        else:
            year, month = param.split("/")
            article_list = article_list.filter(create_time__year=year, create_time__month=month)

    # 每個後的表模型.objects.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 查詢每個分類名稱以及對應的文章數

    # ret=models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title","c")
    # print(ret)

    # 查詢當前站點的每個分類名稱以及對應的文章數

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 查詢當前站點的每個標籤名稱以及對應的文章數

    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)

    # 查詢當前站點每個年月的名稱以及對應的文章數

    # ret=models.Article.objects.extra(select={"is_recent":"create_time > '2018-09-05'"}).values("title","is_recent")
    # print(ret)

    # 方式1:
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    print(date_list)


# 方式2:

# from django.db.models.functions import TruncMonth
#
# ret=models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate(c=Count("nid")).values_list("month","c")
# print("ret----->",ret)

    return render(request, "home_site.html",
              {"username": username, "blog": blog, "article_list": article_list, "tag_list": tag_list,
               "cate_list": cate_list,"date_list":date_list})

三、展現效果如圖所示;

44-博客系統之我的站點的跳轉過濾功能的實現1

一、urls.py之路由設計,添加有名分組;

"""cnblogs URL Configuration

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    re_path('^$', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),
    # media配置;
    re_path(r'media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
    # 我的站點URL;
    re_path(r'^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),
    #re_path(r'^(?P<username>\w+)/category/.*/$', views.home_site),
    #re_path(r'^(?P<username>\w+)/archive/.*/$', views.home_site),
    re_path(r'^(?P<username>\w+)$', views.home_site),
]

45-博客系統之我的站點頁面的跳轉過濾功能實現2

一、urls.py中,針對於相同視圖函數匹配不一樣的路徑,須要傳入不一樣的參數的解決辦法;

"""cnblogs URL Configuration

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    re_path('^$', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),
    # media配置;
    re_path(r'media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
    # 我的站點下的跳轉URL;# 接受的參數,home_site(request,username,condition,param)
    re_path(r'^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),

    # re_path(r'^(?P<username>\w+)/category/.*/$', views.home_site),
    # re_path(r'^(?P<username>\w+)/archive/.*/$', views.home_site),
    # 我的站點URL;#接收的參數home_site(request,username="cxz")
    re_path(r'^(?P<username>\w+)/$', views.home_site),
]

二、MySQL數據庫針對於create_time有約束的限制,需調整settings.py中的USE_TZ = True改成False;

三、針對於年和月的匹配規則,使用split()方法進行分割處理;

def home_site(request, username, **kwargs):
    """
    我的站點視圖函數
    :param request:
    :return:
    """

    print("kwargs", kwargs)  # 區分訪問是的站點頁面仍是站點下的跳轉頁面;
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查詢當前站點對象

    blog = user.blog

    # 1 當前用戶或者當前站點對應全部文章
    # 基於對象查詢
    # article_list=user.article_set.all()
    # 基於 __

    article_list = models.Article.objects.filter(user=user)

    if kwargs:
        condition = kwargs.get("condition")
        param = kwargs.get("param")  # 2012-12

        if condition == "category":
            article_list = article_list.filter(category__title=param)
        elif condition == "tag":
            article_list = article_list.filter(tags__title=param)
        else:
            year, month = param.split("/")
            article_list = article_list.filter(create_time__year=year, create_time__month=month)

    # 每個後的表模型.objects.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 查詢每個分類名稱以及對應的文章數

    # ret=models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title","c")
    # print(ret)

    # 查詢當前站點的每個分類名稱以及對應的文章數

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 查詢當前站點的每個標籤名稱以及對應的文章數

    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)

    # 查詢當前站點每個年月的名稱以及對應的文章數

    # ret=models.Article.objects.extra(select={"is_recent":"create_time > '2018-09-05'"}).values("title","is_recent")
    # print(ret)

    # 方式1:
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    print(date_list)


# 方式2:

# from django.db.models.functions import TruncMonth
#
# ret=models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate(c=Count("nid")).values_list("month","c")
# print("ret----->",ret)

    return render(request, "home_site.html",
              {"username": username, "blog": blog, "article_list": article_list, "tag_list": tag_list,
               "cate_list": cate_list,"date_list":date_list})

46-博客系統之我的站點頁面的跳轉過濾功能的實現3

一、基於「個人標籤」、「隨筆分類」、「隨筆歸檔」進行跳轉;

home_site.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home_site</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            width: 100%;
            height: 60px;
            background-color: #369;
        }

        .header .title {
            font-size: 18px;
            font-weight: 100;
            line-height: 60px;
            color: white;
            margin-left: 15px;
            margin-top: -10px;

        }

        .backend {
            float: right;
            color: white;
            text-decoration: none;
            font-size: 14px;
            margin-right: 10px;
            margin-top: 10px;
        }

        .pub_info {
            margin-top: 10px;
            color: darkgray;
        }

    </style>
</head>
<body>
<div class="header">
    <div class="content">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="" class="backend">管理</a>
        </p>
    </div>
</div>
<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">個人標籤</div>
                <div class="panel-body">
                    {% for tag in tag_list %}
                        <p><a href="/{{ username }}/tag/{{ tag.0 }}"> {{ tag.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">隨筆分類</div>
                <div class="panel-body">
                    {% for cate in cate_list %}
                         <p><a href="/{{ username }}/category/{{ cate.0 }}"> {{ cate.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>
            <div class="panel panel-success">
                <div class="panel-heading">隨筆歸檔</div>
                <div class="panel-body">
                    {% for date in date_list %}
                        <p><a href="/{{ username }}/archive/{{ date.0 }}"> {{ date.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>

        </div>
        <div class="col-md-9">
            <div class="article_list">
                {% for article in article_list %}
                    <div class="article-item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div class="article-desc">
                            {{ article.desc }}
                        </div>
                    </div>
                    <div class="small pub_info pull-right">
                        <span>發佈於&nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>
                        <span class="glyphicon glyphicon-comment"></span>評論({{ article.comment_count }})
                        <span class="glyphicon glyphicon-thumbs-up"></span>點贊({{ article.up_count }})
                    </div>
                    <hr>
                {% endfor %}
            </div>
        </div>
    </div>
</div>
</body>
</html>

views.py;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo
from blog import models
from django.db.models import Count


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    article_list = models.Article.objects.all()

    return render(request, "index.html", {"article_list": article_list})


def logout(request):
    auth.logout(request)  # 等同於request.session.flush()
    return redirect("/login/")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}

            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})


def home_site(request, username, **kwargs):
    """
    我的站點視圖函數
    :param request:
    :return:
    """

    print("kwargs", kwargs)  # 區分訪問是的站點頁面仍是站點下的跳轉頁面;
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查詢當前站點對象

    blog = user.blog

    # 1 當前用戶或者當前站點對應全部文章
    # 基於對象查詢
    # article_list=user.article_set.all()
    # 基於 __

    article_list = models.Article.objects.filter(user=user)

    if kwargs:
        condition = kwargs.get("condition")
        param = kwargs.get("param")  # 2012-12

        if condition == "category":
            article_list = article_list.filter(category__title=param)
        elif condition == "tag":
            article_list = article_list.filter(tags__title=param)
        else:
            year, month = param.split("-")
            article_list = article_list.filter(create_time__year=year, create_time__month=month)

    # 每個後的表模型.objects.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 查詢每個分類名稱以及對應的文章數

    # ret=models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title","c")
    # print(ret)

    # 查詢當前站點的每個分類名稱以及對應的文章數

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 查詢當前站點的每個標籤名稱以及對應的文章數

    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)

    # 查詢當前站點每個年月的名稱以及對應的文章數

    # ret=models.Article.objects.extra(select={"is_recent":"create_time > '2018-09-05'"}).values("title","is_recent")
    # print(ret)

    # 方式1:
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    print(date_list)


# 方式2:

# from django.db.models.functions import TruncMonth
#
# ret=models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate(c=Count("nid")).values_list("month","c")
# print("ret----->",ret)

    return render(request, "home_site.html",
              {"username": username, "blog": blog, "article_list": article_list, "tag_list": tag_list,
               "cate_list": cate_list,"date_list":date_list})

# def get_classification_data(username):
#     user = UserInfo.objects.filter(username=username).first()
#     blog = user.blog
#     cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
#         "title", "c")
#     tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
#     date_list = models.Article.objects.filter(user=user).extra(
#         select={"y_m_date": "date_format(create_time,'%%y/%%m')"}
#     ).values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c")
#     return {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list}

47-博客系統之文章詳情頁的設計

一、路由urls.py配置;

re_path(r'^(?P<username>\w+)/articles/(?P<article_id>\d+)$', views.article_detail),

48-博客系統之文章詳情頁的構建

一、進行程序解耦合操做,分離base.html,基於{% extends 'base.html' %}進行調用;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home_site</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            width: 100%;
            height: 60px;
            background-color: #369;
        }

        .header .title {
            font-size: 18px;
            font-weight: 100;
            line-height: 60px;
            color: white;
            margin-left: 15px;
            margin-top: -10px;

        }

        .backend {
            float: right;
            color: white;
            text-decoration: none;
            font-size: 14px;
            margin-right: 10px;
            margin-top: 10px;
        }

        .pub_info {
            margin-top: 10px;
            color: darkgray;
        }

    </style>
</head>
<body>
<div class="header">
    <div class="content">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="" class="backend">管理</a>
        </p>
    </div>
</div>
<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">個人標籤</div>
                <div class="panel-body">
                    {% for tag in tag_list %}
                        <p><a href="/{{ username }}/tag/{{ tag.0 }}"> {{ tag.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">隨筆分類</div>
                <div class="panel-body">
                    {% for cate in cate_list %}
                        <p><a href="/{{ username }}/category/{{ cate.0 }}"> {{ cate.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>
            <div class="panel panel-success">
                <div class="panel-heading">隨筆歸檔</div>
                <div class="panel-body">
                    {% for date in date_list %}
                        <p><a href="/{{ username }}/archive/{{ date.0 }}"> {{ date.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>

        </div>
        <div class="col-md-9">
            {% block content %}

            {% endblock %}
        </div>
    </div>
</div>
</body>
</html>

二、生成article_detail.html;

{% extends 'base.html' %}

三、重用的代碼優化,編寫獨立函數進行調用;

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.

from django.http import JsonResponse
from django.contrib import auth
from blog.Myforms import UserForm
from blog.models import UserInfo
from blog import models
from django.db.models import Count


def login(request):
    """
    登陸;
    :param request:
    :return:
    """
    if request.method == "POST":
        response = {"user": None, "msg": None}
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():
            user = auth.authenticate(username=user, password=pwd)
            if user:
                auth.login(request, user)
                response["user"] = user.username
            else:
                response["msg"] = "用戶名或者密碼錯誤!"
        else:
            response["msg"] = "驗證碼錯誤!"
        return JsonResponse(response)
    return render(request, "login.html")


def index(request):
    """
    首頁;
    :param request:
    :return:
    """
    article_list = models.Article.objects.all()

    return render(request, "index.html", {"article_list": article_list})


def logout(request):
    auth.logout(request)  # 等同於request.session.flush()
    return redirect("/login/")


def get_valid_code_img(request):
    """
    基於PIL模塊動態生成響應狀態碼圖片;
    :param request:
    :return:
    """
    from blog.utils.validCode import get_valid_code_img
    data = get_valid_code_img(request)
    return HttpResponse(data)


def register(request):
    """
    註冊;
    :param request:
    :return:
    """
    # if request.method == "POST":
    if request.is_ajax():
        # print(request.POST)
        form = UserForm(request.POST)

        response = {"user": None, "msg": None}
        if form.is_valid():
            response["user"] = form.cleaned_data.get("user")
            # 生成一條用戶記錄;
            user = form.cleaned_data.get("user")
            pwd = form.cleaned_data.get("pwd")
            email = form.cleaned_data.get("email")
            avatar_obj = request.FILES.get("avatar")
            '''
            if avatar_obj:
                user_obj = UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar = avatar_obj )
            else:
                user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
            '''
            extra = {}

            if avatar_obj:
                extra["avatar"] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
        else:
            # print(form.cleaned_data)
            # print(form.errors)
            response["msg"] = form.errors
        return JsonResponse(response)
    form = UserForm()
    return render(request, "register.html", {"form": form})


def get_query_data(username):
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查詢當前站點對象

    blog = user.blog
    # 查詢當前站點的每個分類名稱以及對應的文章數

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    return {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list}


def article_detail(request, username, article_id):
    context = get_query_data(username)
    return render(request, "article_detail.html", context)


def home_site(request, username, **kwargs):
    """
    我的站點視圖函數
    :param request:
    :return:
    """

    print("kwargs", kwargs)  # 區分訪問是的站點頁面仍是站點下的跳轉頁面;
    print("username", username)
    user = UserInfo.objects.filter(username=username).first()
    # 判斷用戶是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查詢當前站點對象

    blog = user.blog

    # 1 當前用戶或者當前站點對應全部文章
    # 基於對象查詢
    # article_list=user.article_set.all()
    # 基於 __

    article_list = models.Article.objects.filter(user=user)

    if kwargs:
        condition = kwargs.get("condition")
        param = kwargs.get("param")  # 2012-12

        if condition == "category":
            article_list = article_list.filter(category__title=param)
        elif condition == "tag":
            article_list = article_list.filter(tags__title=param)
        else:
            year, month = param.split("-")
            article_list = article_list.filter(create_time__year=year, create_time__month=month)

    # 每個後的表模型.objects.values("pk").annotate(聚合函數(關聯表__統計字段)).values("表模型的全部字段以及統計字段")

    # 查詢每個分類名稱以及對應的文章數

    # ret=models.Category.objects.values("pk").annotate(c=Count("article__title")).values("title","c")
    # print(ret)

    # 查詢當前站點的每個分類名稱以及對應的文章數

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    print(cate_list)

    # 查詢當前站點的每個標籤名稱以及對應的文章數

    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    print(tag_list)

    # 查詢當前站點每個年月的名稱以及對應的文章數

    # ret=models.Article.objects.extra(select={"is_recent":"create_time > '2018-09-05'"}).values("title","is_recent")
    # print(ret)

    # 方式1:
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    print(date_list)

    # 方式2:

    # from django.db.models.functions import TruncMonth
    #
    # ret=models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate(c=Count("nid")).values_list("month","c")
    # print("ret----->",ret)

    return render(request, "home_site.html",
                  {"username": username, "blog": blog, "article_list": article_list, "tag_list": tag_list,
                   "cate_list": cate_list, "date_list": date_list})

49-博客系統之文章詳情頁的inclution_tag

一、配置base.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home_site</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            width: 100%;
            height: 60px;
            background-color: #369;
        }

        .header .title {
            font-size: 18px;
            font-weight: 100;
            line-height: 60px;
            color: white;
            margin-left: 15px;
            margin-top: -10px;

        }

        .backend {
            float: right;
            color: white;
            text-decoration: none;
            font-size: 14px;
            margin-right: 10px;
            margin-top: 10px;
        }

        .pub_info {
            margin-top: 10px;
            color: darkgray;
        }

    </style>
</head>
<body>
<div class="header">
    <div class="content">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="" class="backend">管理</a>
        </p>
    </div>
</div>
<div class="container">
    <div class="row">
        <div class="col-md-3 menu">
            {% load my_tags %}
            {% get_classification_style username %}

        </div>
        <div class="col-md-9">
            {% block content %}

            {% endblock %}
        </div>
    </div>
</div>
</body>
</html>

二、引入自定義標籤templatetags;

三、使用register.inclusion_tag("classification.html")

# @register.simple_tag
@register.inclusion_tag("classification.html")
def get_classification_style(username):
    user = models.UserInfo.objects.filter(username=username).first()
    # 查詢當前站點對象
    blog = user.blog
    # 查詢當前站點的每個分類名稱以及對應的文章數
    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y-%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    return {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list}

四、整體來說,下降程序耦合度,提升可拓展性;

<div>
    <div class="panel panel-warning">
        <div class="panel-heading">個人標籤</div>
        <div class="panel-body">
            {% for tag in tag_list %}
                <p><a href="/{{ username }}/tag/{{ tag.0 }}"> {{ tag.0 }}({{ tag.1 }})</a></p>
            {% endfor %}

        </div>
    </div>
    <div class="panel panel-danger">
        <div class="panel-heading">隨筆分類</div>
        <div class="panel-body">
            {% for cate in cate_list %}
                <p><a href="/{{ username }}/category/{{ cate.0 }}"> {{ cate.0 }}({{ tag.1 }})</a></p>
            {% endfor %}

        </div>
    </div>
    <div class="panel panel-success">
        <div class="panel-heading">隨筆歸檔</div>
        <div class="panel-body">
            {% for date in date_list %}
                <p><a href="/{{ username }}/archive/{{ date.0 }}"> {{ date.0 }}({{ tag.1 }})</a></p>
            {% endfor %}

        </div>
    </div>
</div>

50-博客系統之文章詳情頁渲染標籤的標籤字符串轉義1

一、Django內部將標籤字符串作了轉義處理;

二、article_detail.html;

{% extends 'base.html' %}

{% block content %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
    {{ article_obj.content }}

    </div>
{% endblock %}

51-博客系統之文章詳情頁渲染的標籤字符串轉義2

一、設置safe屬性,防止xss攻擊;

 

二、article_detail.html;

{% extends 'base.html' %}

{% block content %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
    {{ article_obj.content|safe }}

    </div>
{% endblock %}

52-博客系統之文章點贊樣式的構建

一、點讚的樣式仿照博客園進行構建,而且拆分獨立css樣式文件,使用link方法進行引入;

article_detail.html;

{% extends 'base.html' %}

{% block content %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div id="div_digg">
        <div class="diggit">
            <span class="diggnum" id="digg_count">1</span>
        </div>
        <div class="buryit">
            <span class="burynum" id="bury_count">0</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips" style="color:red;"></div>
    </div>
{% endblock %}

home_site.css;

* {
    margin: 0;
    padding: 0;
}

.header {
    width: 100%;
    height: 60px;
    background-color: #369;
}

.header .title {
    font-size: 18px;
    font-weight: 100;
    line-height: 60px;
    color: white;
    margin-left: 15px;
    margin-top: -10px;

}

.backend {
    float: right;
    color: white;
    text-decoration: none;
    font-size: 14px;
    margin-right: 10px;
    margin-top: 10px;
}

.pub_info {
    margin-top: 10px;
    color: darkgray;
}

article_detail.css;

.article_info .title {
    margin-bottom: 20px;
}

#div_digg {
    float: right;
    margin-bottom: 10px;
    margin-right: 30px;
    font-size: 12px;
    width: 125px;
    text-align: center;
    margin-top: 10px;
}

.diggit {
    float: left;
    width: 46px;
    height: 52px;
    background: url(/static/blog/img/upup.gif) no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.buryit {
    float: right;
    margin-left: 20px;
    width: 46px;
    height: 52px;
    background: url(/static/blog/img/downdown.gif) no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}
.clear{
    clear: both;
}

53-博客系統之文章點贊事件的綁定

一、base.html引入本地靜態jQuery文件;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home_site</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="/static/blog/css/home_site.css">
    <link rel="stylesheet" href="/static/blog/css/article_detail.css">
</head>

二、article_detail.html添加js事件;

{% extends 'base.html' %}

{% block content %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div id="div_digg">
        <div class="diggit action">
            <span class="diggnum" id="digg_count">1</span>
        </div>
        <div class="buryit action">
            <span class="burynum" id="bury_count">0</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips" style="color:red;"></div>
    </div>
    <script>
    $("#div_digg .action").click(function () {
        var is_up = $(this).hasClass("diggit")
        alert(is_up)
    })
    </script>
{% endblock %}

54-博客系統之文章點讚的保存

一、綁定Ajax事件;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div id="div_digg">
        <div class="diggit action">
            <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
        </div>
        <div class="buryit action">
            <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips" style="color:red;"></div>
    </div>
    <script>
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            alert(is_up)

            //傳Ajax事件;
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data)
                }
            })
        });
    </script>
{% endblock %}

二、基於digg視圖函數進行數據的添加;

def digg(request):
    """
    點贊視圖函數;
    :param request:
    :return:
    """

    print(request.POST)
    article_id = request.POST.get("article_id")
    is_up = json.loads(request.POST.get("is_up"))
    # 點贊人即當前登陸人;

    user_id = request.user.pk
    ard = models.ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
    return HttpResponse("ok")

三、新增urls.py下的digg視圖;

"""cnblogs URL Configuration

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    re_path('^$', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),
    path('digg/', views.digg),
    # media配置;
    re_path(r'media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
    re_path(r'^(?P<username>\w+)/articles/(?P<article_id>\d+)$', views.article_detail),
    # 我的站點下的跳轉URL;# 接受的參數,home_site(request,username,condition,param)
    re_path(r'^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),

    # re_path(r'^(?P<username>\w+)/category/.*/$', views.home_site),
    # re_path(r'^(?P<username>\w+)/archive/.*/$', views.home_site),
    # 我的站點URL;#接收的參數home_site(request,username="cxz")
    re_path(r'^(?P<username>\w+)/$', views.home_site),
]

55-博客系統之文章點贊數的數據同步

一、經過update方法像數據庫中新增數據;

def digg(request):
    """
    點贊視圖函數;
    :param request:
    :return:
    """

    print(request.POST)
    article_id = request.POST.get("article_id")
    is_up = json.loads(request.POST.get("is_up"))
    # 點贊人即當前登陸人;

    user_id = request.user.pk
    ard = models.ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
    if is_up:
        models.Article.objects.filter(pk=article_id).update(up_count=F("up_count") + 1)
    return HttpResponse("ok")

56-博客系統之文章點讚的提示重複操做

一、評論與點贊只容許一次的邏輯以及提示消息;

def digg(request):
    """
    點贊視圖函數;
    :param request:
    :return:
    """

    print(request.POST)
    article_id = request.POST.get("article_id")
    is_up = json.loads(request.POST.get("is_up"))
    # 點贊、點踩的人即當前登陸人;

    user_id = request.user.pk
    obj = models.ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
    response = {"state": True}
    if not obj:
        ard = models.ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)

        queryset = models.Article.objects.filter(pk=article_id)
        if is_up:
            queryset.update(up_count=F("up_count") + 1)
        else:
            queryset.update(down_count=F("down_count") + 1)
    else:
        response["state"] = False
        response["handled"] = obj.is_up

    return JsonResponse(response)

二、前端js代碼的業務邏輯;

 <script>
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
           // alert(is_up)

            //傳Ajax事件;
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state){

                    }else {
                        if (data.handled){
                            $("#digg_tips").html("您已經推薦過!")
                        }else{
                            $("#digg_tips").html("您已經反對過!")
                        }
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        },1000)
                    }
                }
            })
        });
    </script>

57-博客系統之文章點贊數的Ajax更新

一、點贊功能的局部刷新功能;

  <script>
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        if (is_up) {
                            var val = parseInt($("#digg_count").text());
                            $("#digg_count").text(val + 1);
                        } else {
                            var val = parseInt($("#bury_count").text());
                            $("#bury_count").text(val + 1);
                        }
                    } else {
                        if (data.handled) {
                            $("#digg_tips").html("您已經推薦過!")
                        } else {
                            $("#digg_tips").html("您已經反對過!")
                        }
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
    </script>

58-博客系統之文章點贊代碼的優化

一、減小重複代碼,提升程序精簡性;

二、三元運算以及$obj = $(this).children("span")的使用;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div id="div_digg">
        <div class="diggit action">
            <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
        </div>
        <div class="buryit action">
            <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips" style="color:red;"></div>
    </div>
    <script>
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
    </script>
{% endblock %}

59-博客系統之評論功能的實現流程

一、評論功能設計思路;

60-博客系統之評論樣式

一、評論功能樣式肯定;

article_detail.html;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts">
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
    </script>
{% endblock %}

二、評論功能組件設置之——發表評論、暱稱(動態引用)、評論頭像、評論內容、提交評論;

61-博客系統之提交根評論

一、提交評論&保存評論;

二、清除評論框操做;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts">
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        $(".common_btn").click(function () {
            var pid = "";
            var content = $("#comment_content").val();
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid:pid,
                },
                success: function (data) {
                    console.log(data);
                    //清空評論框;
                    $("#comment_content").val("")
                }
            })
        })
    </script>
{% endblock %}

comment視圖函數;

 

def comment(request):
    print(request.POST)
    article_id = request.POST.get("article_id")
    pid = request.POST.get("pid")
    content = request.POST.get("content")
    user_id = request.user.pk
    comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,
                                                parent_comment_id=pid)
    return HttpResponse("comment")

62-博客系統之render顯示根評論

評論列表的render顯示;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts">
        <p>評論列表</p>
        <ul class="list-group comment_list">
            {% for comment in comment_list %}
                <li class="list-group-item">
                    <div>
                        <a href="">#{{ forloop.counter }}樓</a> &nbsp;&nbsp;
                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                        <a href=""><span>{{ comment.user.username }}</span></a> &nbsp;&nbsp;
                        <a href="" class="pull-right">回覆</a>
                    </div>
                    <div class="comment_con">
                        <p>{{ comment.content }}</p>
                    </div>
                </li>

            {% endfor %}

        </ul>
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        $(".common_btn").click(function () {
            var pid = "";
            var content = $("#comment_content").val();
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    //清空評論框;
                    $("#comment_content").val("")
                }
            })
        })
    </script>
{% endblock %}

article_detail.css;

.article_info .title {
    margin-bottom: 20px;
}

#div_digg {
    float: right;
    margin-bottom: 10px;
    margin-right: 30px;
    font-size: 12px;
    width: 125px;
    text-align: center;
    margin-top: 10px;
}

.diggit {
    float: left;
    width: 46px;
    height: 52px;
    background: url(/static/blog/img/upup.gif) no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.buryit {
    float: right;
    margin-left: 20px;
    width: 46px;
    height: 52px;
    background: url(/static/blog/img/downdown.gif) no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.clear {
    clear: both;
}

input.author {
    background-image: url(/static/blog/img/icon_form.gif);
    background-repeat: no-repeat;
    border: 1px solid #ccc;
    padding: 4px 4px 4px 30px;
    width: 300px;
    font-size: 13px;
    background-position: 3px -3px;
}
.comment_con{
    margin-top: 10px;
}

 

63-博客系統之Ajax顯示根評論

一、基於Ajax技術展現的評論效果;

二、article_detail.html;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts">
        <p>評論列表</p>
        <ul class="list-group comment_list">
            {% for comment in comment_list %}
                <li class="list-group-item">
                    <div>
                        <a href="">#{{ forloop.counter }}樓</a> &nbsp;&nbsp;
                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                        <a href=""><span>{{ comment.user.username }}</span></a> &nbsp;&nbsp;
                        <a href="" class="pull-right">回覆</a>
                    </div>
                    <div class="comment_con">
                        <p>{{ comment.content }}</p>
                    </div>
                </li>

            {% endfor %}

        </ul>
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        $(".common_btn").click(function () {
            var pid = "";
            var content = $("#comment_content").val();
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var username = data.username;
                    var content = data.content;
                    var s = `
                    <li class="list-group-item">
                    <div>
                        <span>${create_time}</span> &nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>`;
                    $("ul.comment_list").append(s);

                    //清空評論框;
                    $("#comment_content").val("")
                }
            })
        })
    </script>
{% endblock %}

三、comment視圖函數;

def comment(request):
    print(request.POST)
    article_id = request.POST.get("article_id")
    pid = request.POST.get("pid")
    content = request.POST.get("content")
    user_id = request.user.pk
    comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,
                                                parent_comment_id=pid)
    response = {}
    response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X")
    response["username"] = request.user.username
    response["content"] = content
    return JsonResponse(response)

 

64-博客系統之回覆按鈕事件

一、點擊「回覆」按鈕,光標自動跳轉至回覆欄;

二、回覆的對象@形式出現;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts">
        <p>評論列表</p>
        <ul class="list-group comment_list">
            {% for comment in comment_list %}
                <li class="list-group-item">
                    <div>
                        <a href="">#{{ forloop.counter }}樓</a> &nbsp;&nbsp;
                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                        <a href=""><span>{{ comment.user.username }}</span></a> &nbsp;&nbsp;
                        <a  class="pull-right reply_btn" username = "{{ comment.user.username }}" >回覆</a>
                    </div>
                    <div class="comment_con">
                        <p>{{ comment.content }}</p>
                    </div>
                </li>

            {% endfor %}

        </ul>
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        $(".common_btn").click(function () {
            var pid = "";
            var content = $("#comment_content").val();
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var username = data.username;
                    var content = data.content;
                    var s = `
                    <li class="list-group-item">
                    <div>
                        <span>${create_time}</span> &nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>`;
                    $("ul.comment_list").append(s);

                    //清空評論框;
                    $("#comment_content").val("")
                }
            })
        });

    //回覆按鈕事件;
    $(".reply_btn").click(function () {
        $("#comment_content").focus();
        var val = "@"+$(this).attr("username")+"\n";
        $("#comment_content").val(val)
    })
    </script>
{% endblock %}

65-博客系統之提交子評論

一、字評論提交之pid號判斷處理;

二、清空評論框的pid值;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts">
        <p>評論列表</p>
        <ul class="list-group comment_list">
            {% for comment in comment_list %}
                <li class="list-group-item">
                    <div>
                        <a href="">#{{ forloop.counter }}樓</a> &nbsp;&nbsp;
                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                        <a href=""><span>{{ comment.user.username }}</span></a> &nbsp;&nbsp;
                        <a class="pull-right reply_btn" username="{{ comment.user.username }} "
                           comment_pk="{{ comment.pk }}">回覆</a>
                    </div>
                    <div class="comment_con">
                        <p>{{ comment.content }}</p>
                    </div>
                </li>

            {% endfor %}

        </ul>
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        var pid = "";
        $(".common_btn").click(function () {

            var content = $("#comment_content").val();
            if (pid) {
                var index = content.indexOf("\n");
                content = content.slice(index + 1)
            }
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var username = data.username;
                    var content = data.content;
                    var s = `
                    <li class="list-group-item">
                    <div>
                        <span>${create_time}</span> &nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>`;
                    $("ul.comment_list").append(s);

                    //清空評論框;
                    pid = "";
                    $("#comment_content").val("")
                }
            })
        });

        //回覆按鈕事件;
        $(".reply_btn").click(function () {
            $("#comment_content").focus();
            var val = "@" + $(this).attr("username") + "\n";
            $("#comment_content").val(val);
            pid = $(this).attr("comment_pk");
        })
    </script>
{% endblock %}

66-博客系統之render顯示

一、經過render方法進行子評論的顯示;

二、Bootstrap的well屬性的引用;

                 {% if comment.parent_comment_id %}
                        <div class="pid_info well">
                            <p>
                                {{ comment.parent_comment.user.username }}:{{ comment.parent_comment.content }}
                            </p>
                        </div>

                    {% endif %}

 

67-博客系統之Ajax顯示子評論的思路

一、基於Ajax實現局部刷新功能;

        var pid = "";
        $(".common_btn").click(function () {

            var content = $("#comment_content").val();
            if (pid) {
                var index = content.indexOf("\n");
                content = content.slice(index + 1)
            }
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var username = data.username;
                    var content = data.content;
                    var s = `
                    <li class="list-group-item">
                    <div>
                        <span>${create_time}</span> &nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>`;
                    $("ul.comment_list").append(s);

                    //清空評論框;
                    pid = "";
                    $("#comment_content").val("")
                }
            })
        });

68-博客系統之評論樹簡介

一、遞歸展現數據的優缺點;

69-博客系統之評論樹的請求數據

一、構建評論樹的url以及視圖函數;

    path('get_comment_tree/', views.get_comment_tree),
def get_comment_tree(request):
    article_id = request.GET.get("article_id")
    ret = list(models.Comment.objects.filter(article_id=article_id).values("pk", "content", "parent_comment_id"))
    return JsonResponse(ret, safe=False)

 

 

70-博客系統之展開評論樹

一、點擊評論樹展現根評論;

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts list-group">
        <p class="tree_btn">評論樹</p>
        <div class="comment_tree">


        </div>
        <script>
            $(".tree_btn").click(function () {

                $.ajax({
                    url: "/get_comment_tree",
                    type: "get",
                    data: {
                        article_id: "{{ article_obj.pk }}"
                    },
                    success: function (data) {
                        console.log(data)
                        $.each(data, function (index, comment_object) {

                            var pk = comment_object.pk;
                            var content = comment_object.content;
                            var parent_comment_id = comment_object.parent_comment_id;
                            if (!parent_comment_id) {
                                var s = '<div comment_id=' + pk + '><span>' + content + '</span> </div>';
                                $(".comment_tree").append(s)
                            }
                        })

                    }
                })
            })
        </script>
        <p>評論列表</p>
        <ul class="list-group comment_list">
            {% for comment in comment_list %}
                <li class="list-group-item">
                    <div>
                        <a href="">#{{ forloop.counter }}樓</a> &nbsp;&nbsp;
                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                        <a href=""><span>{{ comment.user.username }}</span></a> &nbsp;&nbsp;
                        <a class="pull-right reply_btn" username="{{ comment.user.username }} "
                           comment_pk="{{ comment.pk }}">回覆</a>
                    </div>
                    {% if comment.parent_comment_id %}
                        <div class="pid_info well">
                            <p>
                                {{ comment.parent_comment.user.username }}:{{ comment.parent_comment.content }}
                            </p>
                        </div>

                    {% endif %}
                    <div class="comment_con">
                        <p>{{ comment.content }}</p>
                    </div>
                </li>

            {% endfor %}

        </ul>
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        var pid = "";
        $(".common_btn").click(function () {

            var content = $("#comment_content").val();
            if (pid) {
                var index = content.indexOf("\n");
                content = content.slice(index + 1)
            }
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var username = data.username;
                    var content = data.content;
                    var s = `
                    <li class="list-group-item">
                    <div>
                        <span>${create_time}</span> &nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>`;
                    $("ul.comment_list").append(s);

                    //清空評論框;
                    pid = "";
                    $("#comment_content").val("")
                }
            })
        });

        //回覆按鈕事件;
        $(".reply_btn").click(function () {
            $("#comment_content").focus();
            var val = "@" + $(this).attr("username") + "\n";
            $("#comment_content").val(val);
            pid = $(this).attr("comment_pk");
        })
    </script>
{% endblock %}

71-博客系統之展開評論樹2

article_detail.html;

 

{% extends 'base.html' %}

{% block content %}
    {% csrf_token %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}

    </div>
    <div class="clearfix">
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips" style="color:red;"></div>
        </div>
    </div>
    <div class="commonts list-group">
        <p class="tree_btn">評論樹</p>
        <div class="comment_tree">


        </div>
        <script>
            $(".tree_btn").click(function () {

                $.ajax({
                    url: "/get_comment_tree",
                    type: "get",
                    data: {
                        article_id: "{{ article_obj.pk }}"
                    },
                    success: function (data) {
                        console.log(data)
                        $.each(data, function (index, comment_object) {

                            var pk = comment_object.pk;
                            var content = comment_object.content;
                            var parent_comment_id = comment_object.parent_comment_id;
                            var s = '<div class = "comment_item" comment_id=' + pk + '><span>' + content + '</span> </div>';
                            if (!parent_comment_id) {

                                $(".comment_tree").append(s)
                            } else {
                                $("[comment_id=" + parent_comment_id + "]").append(s);
                            }
                        })

                    }
                })
            })
        </script>
        <p>評論列表</p>
        <ul class="list-group comment_list">
            {% for comment in comment_list %}
                <li class="list-group-item">
                    <div>
                        <a href="">#{{ forloop.counter }}樓</a> &nbsp;&nbsp;
                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span> &nbsp;&nbsp;
                        <a href=""><span>{{ comment.user.username }}</span></a> &nbsp;&nbsp;
                        <a class="pull-right reply_btn" username="{{ comment.user.username }} "
                           comment_pk="{{ comment.pk }}">回覆</a>
                    </div>
                    {% if comment.parent_comment_id %}
                        <div class="pid_info well">
                            <p>
                                {{ comment.parent_comment.user.username }}:{{ comment.parent_comment.content }}
                            </p>
                        </div>

                    {% endif %}
                    <div class="comment_con">
                        <p>{{ comment.content }}</p>
                    </div>
                </li>

            {% endfor %}

        </ul>
        <p>發表評論</p>
        <p>
            暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                      value="{{ request.user.username }}">
        </p>
        <p>評論內容:</p>
        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
        <p>
            <button class="btn btn-default common_btn">提交評論</button>
        </p>
    </div>
    <script>
        //點贊請求;
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
            // alert(is_up)

            //傳Ajax事件;
            $obj = $(this).children("span");
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id": "{{ article_obj.pk }}",

                },
                success: function (data) {
                    console.log(data);
                    if (data.state) {
                        var val = parseInt($("#digg_count").text());
                        $obj.text(val + 1);

                    } else {
                        var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                        $("#digg_tips").html(val);
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 1000)
                    }
                }
            })
        });
        //評論請求;
        var pid = "";
        $(".common_btn").click(function () {

            var content = $("#comment_content").val();
            if (pid) {
                var index = content.indexOf("\n");
                content = content.slice(index + 1)
            }
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                    "article_id": "{{ article_obj.pk }}",
                    "content": content,
                    pid: pid,
                },
                success: function (data) {
                    console.log(data);
                    var create_time = data.create_time;
                    var username = data.username;
                    var content = data.content;
                    var s = `
                    <li class="list-group-item">
                    <div>
                        <span>${create_time}</span> &nbsp;&nbsp;
                        <a href=""><span>${username}</span></a>
                    </div>
                    <div class="comment_con">
                        <p>${content}</p>
                    </div>
                </li>`;
                    $("ul.comment_list").append(s);

                    //清空評論框;
                    pid = "";
                    $("#comment_content").val("")
                }
            })
        });

        //回覆按鈕事件;
        $(".reply_btn").click(function () {
            $("#comment_content").focus();
            var val = "@" + $(this).attr("username") + "\n";
            $("#comment_content").val(val);
            pid = $(this).attr("comment_pk");
        })
    </script>
{% endblock %}

72-博客系統之評論樹的思考1

基於主鍵的order_by設置;

def get_comment_tree(request):
    article_id = request.GET.get("article_id")
    ret = list(models.Comment.objects.filter(article_id=article_id).order_by("pk").values("pk", "content", "parent_comment_id"))
    return JsonResponse(ret, safe=False)

73-博客系統之評論樹的思考2

一、評論樹再也不綁定click事件,直接經過Ajax進行展現;

 <script>
            $.ajax({
                url: "/get_comment_tree",
                type: "get",
                data: {
                    article_id: "{{ article_obj.pk }}"
                },
                success: function (comment_list) {
                    console.log(comment_list);
                    $.each(comment_list, function (index, comment_object) {

                        var pk = comment_object.pk;
                        var content = comment_object.content;
                        var parent_comment_id = comment_object.parent_comment_id;
                        var s = '<div class = "comment_item" comment_id=' + pk + '><span>' + content + '</span> </div>';
                        if (!parent_comment_id) {

                            $(".comment_tree").append(s)
                        } else {
                            $("[comment_id=" + parent_comment_id + "]").append(s);
                        }
                    })

                }
            });
        </script>

74-博客系統之評論事務操做

一、Django中事物的引入,with transaction.atomic()方法的使用;

二、comment視圖函數的寫法;

def comment(request):
    print(request.POST)
    article_id = request.POST.get("article_id")
    pid = request.POST.get("pid")
    content = request.POST.get("content")
    user_id = request.user.pk
    #綁定事物操做;
    with transaction.atomic():
        comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,
                                                    parent_comment_id=pid)
        models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)
    response = {}
    response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X")
    response["username"] = request.user.username
    response["content"] = content
    return JsonResponse(response)

75-博客系統之評論的郵件發送new

一、settings.py文件中配置郵箱信息;

EMAIL_HOST = 'smtp.exmail.qq.com'  # 若是是 163 改爲 smtp.163.com
EMAIL_PORT = 465
EMAIL_HOST_USER = '290799238@qq.com'  # 賬號
EMAIL_HOST_PASSWORD = 'hmefdscufpbnxafbjib'  # 密碼
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_USE_SSL = True

二、comment視圖函數;

 

def comment(request):
    print(request.POST)
    article_id = request.POST.get("article_id")
    pid = request.POST.get("pid")
    content = request.POST.get("content")
    user_id = request.user.pk
    article_obj = models.Article.objects.filter(pk=article_id).first()
    # 綁定事物操做;
    with transaction.atomic():
        comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,
                                                    parent_comment_id=pid)
        models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)
    response = {}
    response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X")
    response["username"] = request.user.username
    response["content"] = content
    # 發送郵件;
    from django.core.mail import send_mail
    from cnblogs import settings
    send_mail(
        "您的文章%s新增了一條內容" % article_obj.title,
        content,
        settings.EMAIL_HOST_USER,
        ["tqtl@tqtl.org"]
    )
    # import threading
    # t = threading.Thread(target=send_mail,args = (
    #     "您的文章%s新增了一條內容" % article_obj.title,
    #     content,
    #     settings.EMAIL_HOST_USER,
    #     ["tqtl@tqtl.org"]
    #
    # ))
    # t.start()
    return JsonResponse(response)

76-博客系統以後臺管理頁面的編輯功能

77-博客系統以後臺管理的編輯器引入和參數

一、kindeditor官網;http://kindeditor.net/demo.php

二、kindEditor在線使用說明;http://kindeditor.net/doc.php

78-博客系統之文本編輯器的上傳功能1

79-博客系統之文本編輯器的上傳功能2

80-博客系統之文章摘要的保存

81-博客系統之bs4的簡單應用

82-博客系統之bs4模塊防護xss攻擊

相關文章
相關標籤/搜索