DAY87-BBS專案(一) 資料庫設計與簡單登陸、驗證碼
阿新 • • 發佈:2018-11-27
一、BBS專案之專案分析
專案流程: 1 搞清楚需求(產品經理) (1) 基於使用者認證元件和Ajax實現登入驗證(圖片驗證碼) (2) 基於forms元件和Ajax實現註冊功能 (3) 設計系統首頁(文章列表渲染) (4) 設計個人站點頁面---跨表查詢,分組查詢 (5) 文章詳情頁 (6) 實現文章點贊功能 (7) 實現文章的評論 ---文章的評論 ---評論的評論 (8) 副文字編輯框 和 防止xss攻擊(防止別人提交js程式碼) 2 設計表結構 3 按著每一個功能分別進行開發 4 功能測試 5 專案部署上線
二、資料庫設計
1.分析資料表以及表關係
使用者表:UserInfo
個人站點表:blog
文章表:Article
評論表:commit
點贊點踩表:upanddown
文章分類表:category
文章標籤表:tag
2.設計欄位
User:繼承AbstractUser,使用者表 nid phone avatar 使用者頭像 blog Blog:站點 nid title site_name theme category:分類 nid title blog 跟blog一對多 tag:(文章關鍵字) nid title blog 跟blog一對多 article:文章 nid title desc 摘要 create_time auto_add_now:當該條記錄建立時,自動添加當前時間 content 文章內容 category 一對多 blog 一對多 tag 多對多 commit:評論 nid user 哪個使用者 article 對哪篇文章 content 評論了什麼內容 commit_time 時間 parent_id 子評論 UpAndDown:點贊 nid user article is_up
3.建立資料庫
from django.db import models from django.contrib.auth.models import AbstractUser # Create your models here. class UserInfo(AbstractUser): nid = models.AutoField(primary_key=True) # 電話可以為空 phone = models.CharField(max_length=32, null=True) # 頭像 avatar = models.FileField(upload_to='avatar/', default='/static/image/default.png') # 站點 blog = models.OneToOneField(to='Blog', to_field='nid') # 使用者和使用者的站點應該是聯合唯一的 class Mate: unique_together = (('username', 'blog'),) class Blog(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=64) # 站點路徑 site_name = models.CharField(max_length=32) # 主題 theme = models.CharField(max_length=64) # 分類 class Category(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=64) # 個人站點可以擁有多個分類 blog = models.ForeignKey(to='Blog', to_field='nid', null=True) # 標籤 class Tag(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=64) # 個人站點可以擁有多個標籤 blog = models.ForeignKey(to='Blog', to_field='nid', null=True) # 文章 class Article(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=64) # 文章簡介 desc = models.CharField(max_length=255) # 文章內容 content = models.TextField() # 建立時間 create_time = models.DateTimeField(auto_now_add=True) # 個人站點可以擁有多篇文章 blog = models.ForeignKey(to='Blog', to_field='nid', null=True) # 一個分類可以擁有多篇文章 category = models.ForeignKey(to='Category', to_field='nid', null=True) # 文章和標籤是多對多的關係,一篇文章可以由多個標籤,一個標籤可以給多篇文章使用 # 手動建立第三張表 tag = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag')) # 多對多第三張表 class Article2Tag(models.Model): nid = models.AutoField(primary_key=True) tag = models.ForeignKey(to='Tag', to_field='nid') article = models.ForeignKey(to='Article', to_field='nid') class Mate: unique_together = (('tag', 'article'),) # 評論 class Commit(models.Model): nid = models.AutoField(primary_key=True) # 評論內容 content = models.TextField() # 評論時間 create_time = models.DateTimeField(auto_now_add=True) # 可以對評論作出評論,設定一個欄位用來表示是對哪條評論做出的評論 # 方法1 # parent_id = models.ForeignKey(to='Commit',to_field='nid') # 方法2 parent_id = models.ForeignKey(to='self',to_field='nid') # 一個使用者可以評論多條 user = models.ForeignKey(to='UserInfo', to_field='nid') # 一篇文章可以有多條評論 article = models.ForeignKey(to='Article', to_field='nid') # 點贊 class UpAndDown(models.Model): nid = models.AutoField(primary_key=True) # 一個使用者可以給多篇文章點贊或踩一下 user = models.ForeignKey(to='UserInfo', to_field='nid') # 一篇文章可以有多個贊和踩 article = models.ForeignKey(to='Article', to_field='nid') # 1是贊,0是踩 is_up = models.BooleanField() class Meta: # 一個使用者只能對一篇文章贊或踩,所以要做聯合唯一 unique_together = (('user', 'article'),)
三、專案配置
setting.py
#連結資料庫
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'bbs',
'POST': 3306,
'HOST': '127.0.0.1',
'USER': 'root',
'PASSWORD': 'root'
}
}
#靜態檔案路徑配置
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
#auth元件authinfo表路徑
AUTH_USER_MODEL = 'blog.UserInfo'
四、登入功能以及驗證碼
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登入</title>
{% load static %}
<link rel="stylesheet" href="{% get_static_prefix %}bootstrap-3.3.7-dist/css/bootstrap.css">
<script src="{% get_static_prefix %}jquery-3.3.1.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<h1 style="text-align: center">登入</h1>
<form>
{% csrf_token %}
<div class="form-group">
<label for="name">使用者名稱</label>
<input type="text" class="form-control" id="name" placeholder="使用者名稱" required>
</div>
<div class="form-group">
<label for="pwd">密碼</label>
<input type="password" class="form-control" id="pwd" placeholder="密碼" required>
</div>
<div class="form-group">
<label for="validCode">驗證碼</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="form-control" id="validCode" placeholder="驗證碼不分大小寫" required>
</div>
<div class="col-md-6">
<img src="/get_validCode/" title="60s後失效" height="35" width="200" class="img-rounded"
id="get_validCode_img">
</div>
</div>
</div>
</form>
<button type="button" class="btn btn-primary btn-lg pull-right" id="btn">登入</button>
</div>
</div>
</div>
</body>
<script>
$(function () {
$("#get_validCode_img").click(function () {
$(this)[0].src += '?'
})
});
$('#btn').click(function () {
var da = {'name':$('#name').val(),'pwd':$('#pwd').val(),'validCode':$('#validCode').val(),csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()}
$.ajax({
url:'/login/',
type:'post',
data:da,
success:function (data) {
alert(data)
}
})
})
</script>
</html>
驗證碼
from PIL import Image, ImageDraw, ImageFont
from BBS import common
from io import BytesIO
def get_validCode(request):
# 第一種方式:本地存放固定圖片
# with open('static/1.png','rb') as f:
# data = f.read()
# return HttpResponse(data)
# # 第二種方式:本地存放隨機圖片
# # 生成圖片 new(模式,寬高,顏色)
# img = Image.new('RGB', (200, 35),color=common.get_color())
# # 寫一個空白本地圖片檔案
# with open('ve_code.png', 'wb') as f:
# # 呼叫img物件的save方法儲存到空檔案
# img.save(f,'png')
# # 開啟檔案,再返回
# with open('ve_code.png','rb') as f:
# data = f.read()
# return HttpResponse(data)
# # 第三種方式:在記憶體中存放隨機圖片
# # 生成圖片 new(模式,寬高,顏色)
# img = Image.new('RGB', (200, 35),color=common.get_color())
# # 生成一個空白記憶體檔案
# f = BytesIO()
# # 呼叫img物件的save方法儲存到空記憶體檔案
# img.save(f,'png')
# # 獲取記憶體檔案的內容
# data = f.getvalue()
# return HttpResponse(data)
# 第四種方式:在記憶體中存放隨機圖片,在圖片上加上隨機驗證碼
# 生成圖片物件 new(模式,寬高,顏色)
img = Image.new('RGB', (200, 35), color=common.get_color())
# 生成畫筆物件,並將圖片物件傳入
img_draw = ImageDraw.Draw(img)
# 生成字型物件
font = ImageFont.truetype('static/font/ss.ttf', size=25)
# 將文字用畫筆寫入圖片
# text(座標,文字,顏色,字型)
img_draw.text((50, 0), common.get_ve_code(request), common.get_color(), font)
# 生成一個空白記憶體檔案
f = BytesIO()
img.save(f, 'png')
data = f.getvalue()
return HttpResponse(data)
共用模組
import random
# 產生隨機RGB
def get_color():
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
# 產生隨機驗證碼
def get_ve_code(request):
ve_code = ''
for i in range(5):
number = random.randint(0, 9)
upper = chr(random.randint(97, 122))
lower = chr(random.randint(65, 90))
add = random.choice((number, upper, lower))
ve_code += str(add)
request.session['ve_code']=ve_code
request.session.set_expiry(60)
return ve_code
登入
from django.shortcuts import render, HttpResponse
from django.contrib import auth
# Create your views here.
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
name = request.POST.get('name')
pwd = request.POST.get('pwd')
validCode = request.POST.get('validCode')
user = auth.authenticate(username=name, password=pwd)
validCode_sess = request.session.get('ve_code')
if validCode.upper() != validCode_sess.upper():
return HttpResponse('驗證碼錯誤')
if user is not None:
return HttpResponse('登陸成功')
else:
return HttpResponse('使用者名稱或密碼錯誤')