BBS項目

1、表結構關係圖css

  

 

 2、建表html

from django.db import models

# Create your models here.

from django.contrib.auth.models import AbstractUser


class UserInfo(AbstractUser):
    """
    用戶信息表
    """
    phone = models.CharField(max_length=11, null=True, unique=True)  # 手機號
    avatar = models.FileField(upload_to="avatars/", default="avatars/default.png")  # 頭像

    blog = models.OneToOneField(to="Blog", null=True)

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = "用戶信息"
        verbose_name_plural = verbose_name


class Blog(models.Model):
    """
    博客信息
    """
    title = models.CharField(max_length=64)  # 我的博客標題
    theme = models.CharField(max_length=32)  # 博客主題

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "博客"
        verbose_name_plural = verbose_name


class Category(models.Model):
    """
    我的博客文章分類
    """
    title = models.CharField(max_length=32)  # 分類標題
    blog = models.ForeignKey(to="Blog")  # 外鍵關聯博客,一個博客站點能夠有多個分類

    def __str__(self):
        return "{}-{}".format(self.blog.title, self.title)

    class Meta:
        verbose_name = "文章分類"
        verbose_name_plural = verbose_name


class Tag(models.Model):
    """
    標籤
    """
    title = models.CharField(max_length=32)  # 標籤名
    blog = models.ForeignKey(to="Blog")  # 所屬博客

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "標籤"
        verbose_name_plural = verbose_name


class Article(models.Model):
    """
    文章
    """
    title = models.CharField(max_length=50)  # 文章標題
    desc = models.CharField(max_length=255)  # 文章描述
    create_time = models.DateTimeField(auto_now_add=True)  # 建立時間
    category = models.ForeignKey(to="Category", null=True)  # 文章分類
    user = models.ForeignKey(to="UserInfo")  # 做者
    tags = models.ManyToManyField(  # 文章的標籤
        to="Tag",
        through="Article2Tag",
        through_fields=("article", "tag"),
    )

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "文章"
        verbose_name_plural = verbose_name


class ArticleDetail(models.Model):
    """
    文章詳情表
    """
    content = models.TextField()  # 文章內容
    article = models.OneToOneField(to="Article")

    class Meta:
        verbose_name = "文章詳情"
        verbose_name_plural = verbose_name


class Article2Tag(models.Model):
    """
    文章和標籤的多對多關係表
    """
    article = models.ForeignKey(to="Article")
    tag = models.ForeignKey(to="Tag")

    def __str__(self):
        return "{}-{}".format(self.article, self.tag)

    class Meta:
        unique_together = (("article", "tag"),)
        verbose_name = "文章-標籤"
        verbose_name_plural = verbose_name


class ArticleUpDown(models.Model):
    """
    點贊表
    """
    user = models.ForeignKey(to="UserInfo", null=True)
    article = models.ForeignKey(to="Article", null=True)
    is_up = models.BooleanField(default=True)  # 點贊仍是踩滅

    def __str__(self):
        return "{}-{}".format(self.user_id, self.article_id)

    class Meta:
        unique_together = (("article", "user"),)  # 同一我的只能給一篇文章點一次贊
        verbose_name = "點贊"
        verbose_name_plural = verbose_name


class Comment(models.Model):
    """
    評論表
    """
    article = models.ForeignKey(to="Article")
    user = models.ForeignKey(to="UserInfo")
    content = models.CharField(max_length=255)  # 評論內容
    create_time = models.DateTimeField(auto_now_add=True)

    parent_comment = models.ForeignKey("self", null=True)  # 本身關聯本身

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "評論"
        verbose_name_plural = verbose_name
models.py

  1.多對多三種實現方式前端

  2.聯合惟一python

 

3、登陸jquery

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸</title>
    <link rel="stylesheet" href="/static/css/bootstrap/bootstrap3.3.7-min.css">
    <link rel="stylesheet" href="/static/css/login.css">
</head>
<body>

<div class="container col-md-4 col-md-push-3">
    <form class="form-horizontal" novalidate>
        {% csrf_token %}
        <div class="form-group">
            <label class="col-sm-3 control-label" for="inputUser">用戶名:</label>
            <div class="col-sm-9">
                <input type="text" class="form-control" id="inputUser" placeholder="請輸入用戶名" autofocus="">
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-3 control-label" for="inputPwd">密 碼:</label>
            <div class="col-sm-9">
                <input type="password" class="form-control" id="inputPwd" placeholder="請輸入密碼">
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-3 control-label" for="inputVcode">驗證碼:</label>
            <div class="col-sm-4">
                <input type="text" class="form-control" id="inputVcode" placeholder="請輸入驗證碼">
            </div>
            <div class="col-sm-5" id="divImgVcode">
                <img src="{% url 'v_code' %}" alt="" id="imgVcode">
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-3 col-sm-3">
                <div class="checkbox">
                    <label>
                        <input type="checkbox" id="remember-me"> 記住我
                    </label>
                </div>
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-push-4 col-sm-7">
                <button type="button" class="btn btn-block btn-lg btn-info" id="btnLogin">登陸</button>
                <p id="pErrMsg"></p>
            </div>
        </div>
    </form>

</div>

<script src="/static/js/jquery/jquery3.3.1-min.js"></script>
<script src="/static/js/setAjax.js"></script>
<script>

    $("#btnLogin").click(function () {
        let username = $("#inputUser").val();
        let password = $("#inputPwd").val();
        let vCode = $('#inputVcode').val();
        $.ajax({
            url:{% url 'login' %},
            type: 'post',
            data: {
                username: username,
                password: password,
                vcode:vCode,
            },
            success: function (res) {
                if (res.code !== 0) {
                    // 認證失敗
                    $("#pErrMsg").text(res.msg)
                }
                else {
                    location.href = '{% url 'index' %}'
                }
            }
        })
    });

    $('input').focus(function () {
        $('#pErrMsg').text('')
    });

    let orgUrlLenth = $('#imgVcode')[0].src.length;
    $('#imgVcode').click(function () {
        let timeStamp = new Date().valueOf();
        this.src = this.src.substring(0, orgUrlLenth) + timeStamp;
    })

</script>
</body>
</html>
login.html
from django.shortcuts import render, redirect, HttpResponse
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from django.http import JsonResponse
from django import views
from io import BytesIO
import random


# Create your views here.


class Login(views.View):

    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        res = {'code': 0}
        username = request.POST.get('username')
        password = request.POST.get('password')
        vcode = request.POST.get('vcode')
        if vcode.upper() != request.session.get('vcode').upper():
            res['code'] = 1
            res['msg'] = '驗證碼有誤'
        else:
            # auth認證
            user = authenticate(request, username=username, password=password)
            if user:
                # 認證成功,進行登陸
                login(request, user)
            else:
                res['code'] = 1
                res['msg'] = '用戶名或密碼有誤'
        return JsonResponse(res)


def v_code(request):
    # 隨機顏色,相對較淺
    def random_color1():
        return random.randint(64, 255), random.randint(64, 255), random.randint(64, 255)

    # 隨機顏色,相對較深
    def random_color2():
        return random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)

    # 等機率隨機生成 n 個數字、字母(大小寫)組合的驗證碼列表
    def random_code(n):
        rec_list = []
        while n:
            n -= 1
            rdm_first = random.randint(0, 1)
            if rdm_first == 0:
                rec_list.append(str(random.randint(0, 9)))
            else:
                rdm_second = random.randint(0, 1)
                if rdm_second == 0:
                    rec_list.append(chr(random.randint(65, 90)))
                else:
                    rec_list.append(chr(random.randint(97, 122)))
        return rec_list

    vcode_list = random_code(4)

    # 由最終驗證碼組成的字符串, 存入session中用來校驗
    vcode = ''.join(vcode_list)
    request.session['vcode'] = vcode

    # 生成一張圖片
    img_obj = Image.new(
        'RGB',  # 生成圖片的模式
        (162, 33),  # 大小
        random_color1()  # 顏色
    )

    # 生成一個畫筆,指定畫板爲img_obj
    draw_obj = ImageDraw.Draw(img_obj)

    # 加載本地字體文件,生成字體對象
    font_obj = ImageFont.truetype('static/font/kumo.ttf', size=28)

    # 依次在畫板上寫上n個驗證碼
    for i in range(len(vcode_list)):
        draw_obj.text(
            (i * 32 + 20, 0),  # 座標
            vcode_list[i],  # 內容
            fill=random_color2(),  # 畫筆顏色,即字體顏色
            font=font_obj,  # 字體對象
        )

    # # 加干擾線
    # width = 250  # 圖片寬度(防止越界)
    # height = 35
    # 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_obj.line((x1, y1, x2, y2), fill=random_color())
    #
    # # 加干擾點
    # for i in range(40):
    #     draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=random_color())

    # # 進行模糊處理
    # img_obj = img_obj.filter(ImageFilter.BLUR)

    iof = BytesIO()  # 生成IO句柄
    img_obj.save(iof, 'png')  # 把圖片對象放進IO句柄裏,即保存到內存中
    data = iof.getvalue()  # 從內存中讀取圖片數據

    # 從服務器靜態文件夾內讀取圖片數據
    # with open('static/img/oo.png', 'rb') as f:
    #     data = f.read()

    return HttpResponse(data, content_type='image/png')


@login_required
def index(request):
    user_pro = request.user
    print(user_pro.userinfo.address)
    return HttpResponse('Index')


def log_out(request):
    logout(request)
    return redirect('/login/')
views.py
from django.contrib import admin
from django.urls import path, re_path
from Authapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.Login.as_view(), name='login'),
    path('index/', views.index, name='index'),
    path('logout/', views.log_out, name='logout'),
    re_path('v-code/\d*', views.v_code, name='v_code'),
]
urls.py
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

LOGIN_URL = '/login/' 

AUTH_PROFILE_MODULE = 'Authapp.UserInfo'
settings.py

  注意:ajax

  1. ajax,auth,bootstrap(組長教的)       正則表達式

    python基礎 random.randint()  字母65-90、97-122  chr(數字)  顏色(0~255)三個一組(0,0,0)sql

 

  2. 製做驗證碼數據庫

    1.pillow     import PILdjango

      Image.new()  img對象.filter(ImageFilter.BLUR)        

      ImageFont.truetype()

      ImageDraw.Draw(img對象)  draw對象.text()  draw對象.line()  draw對象.arc()

      點擊切換驗證碼實現方式:

        1.一直加?

        2.加時間戳

        3.加?刪?交替      import  django.views.decorators.cache  import  never_cache (前段禁用緩存, 火狐瀏覽器有bug)    

    2.BytesIO

      BytesIO()

      img對象.save(IO對象,‘png等格式’)

      IO對象.getvalue()

 

    3.HttpResponse  能夠爲 src 提供資源

      HttpResponse(data,content_type='image/png') 返回一張圖片

 

  3.前段JS   focus     blur       jQuery對象$(「 #id 」)[ 0 ] 對象DOM       length       substring()

    Date().valueOf()    p標籤 .text(" ")  location.href="url"  col-sm-offset-4 (push-pull)

 

3、註冊

     1. 上傳頭像,前端

    上傳文件的input 標籤

    <input type="file" accept="image/*" id="inpAvatar">

 

  2. 上傳頭像後臺(views視圖函數)

    接收文件:

    avatar_file = request.FILES.get("avatar")

    保存註冊信息到數據庫:

    models.UserInfo.objects.create_user(**form_obj.cleaned_data, avatar=avatar_file)

    (由於是File文件,錄入數據庫時,會按字段保存路徑,按路徑找目錄保存文件)

  3. 上傳頭像後臺(models模型層)

    UserInfo表中:

      avatar是一個FileField 字段,FileField(upload_to="avatars/",)

      avatar具體保存的是一個路徑,而不是一個文件

      具體保存文件的是:這個路徑對應的目錄(配置了media就另當別論)

      (配置midia後)具體保存文件的目錄是:在上傳路徑前面拼接上media後的新路徑對應的目錄

  3.  關於配置media(不配置就是上面的那樣)

    關於static,經過settings設置別名,即讓別名表明其絕對路徑。放置可提供的靜態文件。

      不能是全部文件都是能夠訪問的,涉及安全、泄密等問題。像用戶上傳的東西要有

      指定的目錄存放。(部署時要作區分)(MEDIA_URL,MEDIA_ROOT是Django提供,也就是說別的就不認識了)

      (這樣用戶上傳的文件是存放在media/ 下了,可是用戶數據庫中相關字段存的仍是原來的路徑,因此用時要拼接)

    1.settings.py

      MEDIA_URL = '/media/'    (# 別名)

      MEDIA_ROOT = os.path.join(BASE_DIR, 'media')     (只有一個目錄,不像static能夠添加多個)

        (給用戶上傳的全部文件(FileField、request.FILES)指定一個存放目錄)

      TEMPLATES 中添加上下文環境(可選配置)(自動把 MEDIA_URL 註冊到前端的模板中)

        'django.template.context_processors.media',  (這樣前端拼接時候,能夠作活路徑)

    2.urls.py

      from django.views.static import serve

      re_path('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})

4、主頁面、我的主頁、分類標籤歸檔頁

   0.關於路由urls :各類路由都是開發者設計的。

 

   1.評論點贊,bootstrap小圖標 

<span class="glyphicon glyphicon-comment">評論({{ article.comment_count }})</span>
<span class="glyphicon glyphicon-thumbs-up">點贊({{ article.up_count }})</span>

   2.模板中,時間格式化  

      模板語言,過濾器

      <span>發佈於&nbsp;{{ article.create_time|date:'Y-m-d H:i:s' }}</span>

   3.二級路由 (名稱空間)

    項目urls: from  django.urls  import  include      from  app01  import  urls  as  app01_urls  (別名)

    app01中urls:  from django.urls import path     from  app01  import  views

           urlpatterns = [ 各類後續path ]

  4.orm 插入原生sql語句

     1.一半一半  (利用extra函數在執行orm查詢的同時,額外執行一段sql語句,子查詢)

    

       2. 對象鏈接數據庫,光標對象執行原生sql

           from  django.db  import  connection

           cusor = connection.cursor()     # 鏈接數據庫,得到一個遊標對象

           cursor.execute(" sql語句 ")  # 遊標處:輸入sql語句

           cursor.fetchall()  # 取查詢結果

  5. 分組、聚合  

     詳見 http://www.cnblogs.com/haiyan123/p/7745536.html

     QuerySet.annotate()    -->   分組,前面查的什麼字段,就按照什麼字段進行分組

                  分組時,給每一個組對象新添加:組屬性(組成員),例如annotate(c=Count(article__title))

                  分組是爲QuerySet中每個對象(即組名對象)生成一個獨立的彙總值

                    是對分組完以後的結果進行的聚合

       QuerySet.aggregate()    -->  聚合,給QuerySet中的每一個對象添加一個新屬性,給一個組進行聚合

                  是QuerySet 的一個終止子句(也就是返回的再也不是一個QuerySet集合的時候)

                 意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。

                 鍵的名稱是按照 "字段名稱__聚合函數的名稱" 自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。

  6. 多條視圖路由整合一條    

        路由中正則表達式(無名分組、有名分組不可混合使用)(位置傳參必需要在關鍵字傳參前面)

        re_path(r"(\d+)/mid/(\w+)",....) 寫了幾個分組就得匹配幾個參數,沒有就算匹配不到

5、文章詳情頁

  1.模板繼承   {%  extends  "xx.html"  %}

  2.inclusion_tag  

    1. 返回一段HTML代碼,用數據填充的

    2. 用法:

      1. 在app下面建立一個名爲 templatetags 的Python Package

      2. 寫個例如「mytags.py」:

        from  django  import  template

        register = template.Library()

        @register.inclusion_tag(file="xx.html")

        def  show_menu(*args):

            ...            (此處不少查詢操做)

            return  {"k1" : "v1"}

            (xx.html 中使用 k1這個變量)

        (用這個自定義標籤只是爲了少書寫查詢語句的代碼,並無減小查詢次數)

  3.點贊

    1.orm事務操做

      from django.db import  transaction

      with  transaction.atomic():

        sql1

        sql2

    2.模板語言

      1.{{ xx }}表示的是單值,不在是變量了,

        因此在js中用到這樣的值了,要用引號 "{{ request.user }}"

      2.把 js 代碼寫入js文件中在導入的時候,由於render渲染時不會去渲染引入的js,因此要處理

        (補) 

  4.QuerySet 惰性求值        

     1.len()  及 count()        

     2,.修改單個屬性,兩個方法的區別     

     3.debug-tool-bar

  5.階段問題transaction.atomic()    {% extends 'xx.html' %}    {% load  mytags %}{% func 'xx.html' %}

     分組、聚合  F、Q  js中正則包裹 /RegExp /  RegExp.test(str)  RegExp.exec(str)

      

 6、文章評論

 

 

5、代碼集

def get_vcode(request):
    # 隨機顏色,相對較淺
    def random_color1():
        return random.randint(64, 255), random.randint(64, 255), random.randint(64, 255)

    # 隨機顏色,相對較深
    def random_color2():
        return random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)

    # 等機率隨機生成 n 個數字、字母(大小寫)組合的驗證碼列表
    def random_code(n):
        rec_list = []
        while n:
            n -= 1
            rdm_first = random.randint(0, 1)
            if rdm_first == 0:
                rec_list.append(str(random.randint(0, 9)))
            else:
                rdm_second = random.randint(0, 1)
                if rdm_second == 0:
                    rec_list.append(chr(random.randint(65, 90)))
                else:
                    rec_list.append(chr(random.randint(97, 122)))
        return rec_list

    vcode_list = random_code(4)

    # 由最終驗證碼組成的字符串, 存入session中用來校驗
    vcode = ''.join(vcode_list)
    request.session['vcode'] = vcode

    # 生成一張圖片
    img_obj = Image.new(
        'RGB',  # 生成圖片的模式
        (162, 33),  # 大小
        random_color1()  # 顏色
    )

    # 生成一個畫筆,指定畫板爲img_obj
    draw_obj = ImageDraw.Draw(img_obj)

    # 加載本地字體文件,生成字體對象
    font_obj = ImageFont.truetype('static/font/kumo.ttf', size=28)

    # 依次在畫板上寫上n個驗證碼
    for i in range(len(vcode_list)):
        draw_obj.text(
            (i * 32 + 20, 0),  # 座標
            vcode_list[i],  # 內容
            fill=random_color2(),  # 畫筆顏色,即字體顏色
            font=font_obj,  # 字體對象
        )

    # # 加干擾線
    # width = 250  # 圖片寬度(防止越界)
    # height = 35
    # 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_obj.line((x1, y1, x2, y2), fill=random_color())
    #
    # # 加干擾點
    # for i in range(40):
    #     draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=random_color())

    # # 進行模糊處理
    # img_obj = img_obj.filter(ImageFilter.BLUR)

    iof = BytesIO()  # 生成IO句柄
    img_obj.save(iof, 'png')  # 把圖片對象放進IO句柄裏,即保存到內存中
    data = iof.getvalue()  # 從內存中讀取圖片數據

    # 從服務器靜態文件夾內讀取圖片數據
    # with open('static/img/oo.png', 'rb') as f:
    #     data = f.read()

    return HttpResponse(data, content_type='image/png')
生成隨機驗證碼

 

  

 

 

 

 

 

 

ok

相關文章
相關標籤/搜索