bbs項目
項目開發(fā)流程
需求分析
架構(gòu)設(shè)計
分組開發(fā)
我們一般情況下都只是作用于這一步
各項測試
交付上線
bbs表設(shè)計
任何一個項目 最最重要的部分都是數(shù)據(jù)庫的表設(shè)計
用戶表
繼承AbstractUser表 來做額外的字段擴展
1.類的繼承
2.配置文件配置
AUTH_USER_MODEL = '應(yīng)用名.類名'
phone
avatar
upload_to='avatar/'
register_time
個人站點表
站點標(biāo)題
站點名稱
站點樣式
模擬
文章標(biāo)簽表
標(biāo)簽名稱
文章分類表
分類名稱
文章表
文章標(biāo)題
文章簡介
文章內(nèi)容
文章日期
# 數(shù)據(jù)庫優(yōu)化字段
點贊數(shù)
點踩數(shù)
評論數(shù)
點贊點踩表
用戶id 一對多字段
文章id 一對多字段
點贊點踩 1/0
評論表
用戶id 一對多字段
文章id 一對多字段
評論內(nèi)容
評論時間
自關(guān)聯(lián)字段 自己跟自己所在的表關(guān)聯(lián)
數(shù)據(jù)庫配置
1.配置文件
2.__init__文件
數(shù)據(jù)庫遷移命令
python3 manage.py makemigrations
python3 manage.py migrate
注冊功能
只要是注冊功能一般都有一定的校驗規(guī)則
我們利用forms組件 來完成注冊的校驗
用戶名
label
error_messages
required
invalid
widget
validators
密碼
確認(rèn)密碼
郵箱
鉤子函數(shù)
校驗用戶名是否已存在
校驗兩次密碼是否一致
一旦你的項目特別龐大 需要用到很多forms組件
那么你可以單獨的將所有forms組件放到一個py文件中或者一個文件下
然后針對不同的功能開設(shè)不同的py文件
單獨的py文件
文件夾
1.py
2.py
3.py
4.py
注冊功能使用的是ajax做后端交互
但是我們用的了form標(biāo)簽
因為form標(biāo)簽有一個自動序列化普通鍵值對的功能
可以方便的將普通鍵值對循環(huán)添加到formdata對象中
label標(biāo)簽在跟input有綁定關(guān)系的前提下
內(nèi)部無論放什么對象 點擊都能夠是對應(yīng)的input框聚焦
img標(biāo)簽src屬性可以放的值
1.圖片的地址
2.圖片的二進制數(shù)據(jù)
3.后端url 自動朝該url發(fā)送get請求
實時展示用戶選擇的頭像
利用內(nèi)置對象fileReader
文件閱讀器在讀取文件的時候 是一個異步io操作
所以你在渲染img標(biāo)簽的時候一定要等待文件閱讀器加載完畢之后再渲染
等待...加載完畢
onload
window.onload = function(){}
fileReader.onload = function(){}
發(fā)送ajax請求
1.ajax提交數(shù)據(jù)基本語法
2.ajax發(fā)送文件需要借助于內(nèi)置對象formdata
ajax發(fā)送formdata對象
需要制定兩個參數(shù)都為false
processData
contentType
后端正常的業(yè)務(wù)邏輯無需多說
一旦報錯之后前端如何對應(yīng)的渲染相應(yīng)的信息
1.你需要研究form組件渲染的input框的id值的特點
id_字段名
2.你又發(fā)現(xiàn)返回的報錯信息 鍵就是一個個的字段名
自己手動拼接處input框的id值
然后利用DOM操作 來操作span標(biāo)簽以及div標(biāo)簽
最后為了功能的健壯性
給所有的input設(shè)置獲取焦點事件
自動移除報錯信息和報錯的樣式
控制字體樣式的文件都是以.ttf結(jié)尾
本周
bbs結(jié)束
今日內(nèi)容
登錄功能
首頁搭建
導(dǎo)航條用戶功能
admin后臺管理
下周安排(15d~22d)
vue前端框架 3~5d
django restframework(******)
路飛項目
git
celery
項目上線
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 注冊功能
url(r'^register/',views.register,name='register'),
# 登錄功能
url(r'^login/',views.login,name='login'),
# 驗證碼圖片
url(r'^get_code/',views.get_code,name='code'),
# 首頁搭建
url(r'^home/',views.home,name='home'),
# 退出登錄
url(r'^logout/',views.logout,name='logout'),
# 修改密碼
url(r'^set_password/',views.set_password,name='set_pwd')
]
from django.shortcuts import render,HttpResponse,redirect,reverse
from app01 import myform
from app01 import models
from django.http import JsonResponse
# 驗證碼相關(guān)
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO, StringIO
# auth模塊校驗密碼
from django.contrib import auth
from django.contrib.auth.decorators import login_required
# Create your views here.
def register(request):
# 生成一個空的forms對象
form_obj = myform.MyRegForm()
if request.method == 'POST':
back_dic = {'code':1000,'msg':''}
# 對用戶提交的數(shù)據(jù)先進行校驗 forms
# 直接使用forms組件的校驗方法,校驗整個的數(shù)據(jù)字典
form_obj = myform.MyRegForm(request.POST)
if form_obj.is_valid():
# 如果數(shù)據(jù)校驗結(jié)果正確
clean_data = form_obj.cleaned_data # 獲取正確的數(shù)據(jù) 4個鍵值對
# 將確認(rèn)密碼的鍵值對彈出,只剩余三個便于創(chuàng)建用戶
clean_data.pop('confirm_password')
# 獲取用戶上傳的文件
file_obj = request.FILES.get('avatar')
# 判斷文件是否存在,用戶是否上傳,如果沒有上傳才會設(shè)置default頭像
if file_obj:
clean_data['avatar'] = file_obj # 四個鍵值對
# 自動創(chuàng)建,使用**直接打散關(guān)鍵字參數(shù)
models.Userinfo.objects.create_user(**clean_data)
# 添加成功界面信息,及跳轉(zhuǎn)
back_dic['msg'] = '注冊成功'
back_dic['url'] = '/login/'
else:
back_dic['code'] = 2000
# 將錯誤信息返回給前端
back_dic['msg'] = form_obj.errors
# 返回給前端字典
return JsonResponse(back_dic)
return render(request,'register.html',locals())
# 登錄功能
def login(request):
if request.method == 'POST':
back_dic = {'code':1000,'msg':''}
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# 1.先校驗驗證碼是否正確 忽略大小寫
if request.session.get('code').upper() == code.upper():
# 2.校驗用戶名密碼是否正確 利用auth模塊
user_obj = auth.authenticate(request,username=username,password=password)
if user_obj:
# 3.保存用戶登錄狀態(tài)
auth.login(request,user_obj)
# 就可以在任意位置通過request.user獲取到當(dāng)前登錄對象 并且 request.user.is_authenticated()判斷當(dāng)前用戶是否登錄
# 返回前端信息,并定向主頁
back_dic['msg'] = '登錄成功'
back_dic['url'] = '/home/'
else:
back_dic['code'] = 2000
back_dic['msg'] = '用戶名或密碼錯誤'
else:
back_dic['code'] = 3000
back_dic['msg'] = '驗證錯誤'
# 返回給前端字典數(shù)據(jù)
return JsonResponse(back_dic)
return render(request,'login.html')
import random
# 給驗證碼的圖片添加隨機顏色
def get_random():
return random.randint(0,255),random.randint(0,255),random.randint(0,255)
# 圖片驗證碼相關(guān)
def get_code(request):
# 推導(dǎo)步驟一:直接發(fā)送后端存在的圖片
# img標(biāo)簽可以直接返回二進制數(shù)據(jù)進行顯示
# with open(r'static/img/02b02.jpg.jpg','rb') as f:
# data = f.read()
# return HttpResponse(data)
# 推導(dǎo)步驟二 利用pillow模塊自動生成圖片
'''
from PIL import Image,ImageDraw,ImageFont
Image 生成圖片
ImageDraw 在圖片上寫字
ImageFont 控制字體的樣式'''
# 生成圖片對象
# img_obj = Image.new('RGB',(360,35),'red') 直接放文件的顏色
# img_obj = Image.new('RGB',(360,35),get_random()) # 放rgb模式(255,23,232)
# # 利用文件操作先保存下來
# with open('xxx.png','wb') as f:
# img_obj.save(f,'png')
# # 然后利用文件操作將圖片數(shù)據(jù)讀取并發(fā)送
# with open(r'xxx.png','rb') as f:
# data = f.read()
# return HttpResponse(data)
# 推導(dǎo)步驟三 臨時存儲數(shù)據(jù)并且能夠隨時取出的地方
'''內(nèi)存管理模塊
from io import BytesIO,StringIO
BytesIO 保存數(shù)據(jù)(并且在獲取的時候,是以二進制的方式給你)
StringIO 保存數(shù)據(jù)(以字符串的形式給你)
'''
# img_obj = Image.new('RGB',(360,35),get_random())
# # # 先生成一個io對象
# # io_obj = BytesIO() # 可以將對象當(dāng)做是文件的句柄
# # # 存儲數(shù)據(jù)
# # img_obj.save(io_obj,'png')
# # # getvalue獲取二進制的數(shù)據(jù)
# # return HttpResponse(io_obj.getvalue())
# 推導(dǎo)步驟四 在圖片上寫字
img_obj = Image.new('RGB',(360,35),get_random())
# 將生成好的圖片對象交給imageDraw
img_draw = ImageDraw.Draw(img_obj) # 生成一個畫筆對象
# 字體樣式,將ttf格式字體,及字體的大小 設(shè)置
img_font = ImageFont.truetype('static/fonts/1.ttf',30)
# 產(chǎn)生一個隨機驗證碼 大小寫英文加數(shù)字 五位,每一位都可以是大小寫數(shù)據(jù)
code= ''
for i in range(5):
# chr 根據(jù)數(shù)字對應(yīng)字符編碼的英文
upper_str = chr(random.randint(65,90))
lower_str = chr(random.randint(97,122))
random_int = str(random.randint(0,9))
# 隨機選取一個字符
tmp = random.choice([upper_str,random_int,lower_str])
# 向圖片中寫入一個((x軸,y軸)坐標(biāo),文本,圖片北京,字體樣式)
img_draw.text((i*60 60,0),tmp,get_random(),img_font)
# 存儲寫的字
code = tmp
print(code)
# 這個驗證碼后面的其他視圖函可能用得上,找到地方保存,并且這個地方的全局視圖函數(shù)都可以訪問
request.session['code'] = code
# 圖片保存
io_obj = BytesIO()
img_obj.save(io_obj,'png')
return HttpResponse(io_obj.getvalue())
# 首頁的搭建
def home(request):
return render(request,'home.html',locals())
# 退出登錄
@login_required
def logout(request):
# 退出登錄
auth.logout(request)
# 重定向到主頁
return redirect(reverse('home'))
@login_required
def set_password(request):
if request.method == 'POST':
old_pwd = request.POST.get('old_password')
new_pwd = request.POST.get('new_password')
confirm_password = request.POST.get('confirm_password')
# 1.先判斷舊密碼是否正確
is_right = request.user.check_password(old_pwd)
if is_right:
# 判斷新密碼與確認(rèn)密碼是否一致
if new_pwd == confirm_password:
# 修改密碼
request.user.set_password(new_pwd)
request.user.save()
# 重定向界面
return redirect(reverse('login'))
else:
return HttpResponse('兩次密碼不一致')
else:
return HttpResponse('原密碼不正確')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 ">
<h2 class="text-center">登錄界面</h2>
<div class="form-group">
<label for="id_username">用戶名</label>
<input type="text" name="username" id="id_username" class="form-control">
</div>
<div class="form-group">
<label for="id_password">密碼</label>
<input type="password" name="password" id="id_password" class="form-control">
</div>
{# 驗證碼框#}
<div class="form-group">
<label for="id_code">驗證碼</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="code" id="id_code" class="form-control">
</div>
<div class="col-md-6">
<img src="/get_code/" alt="" width="360" height="35" id="id_img">
</div>
</div>
</div>
<input type="button" class="btn btn-primary" value="登錄" id="id_submit">
{# // 錯誤信息的展示#}
<span style="color: red;" id="id_error"></span>
</div>
</div>
</div>
<script>
{#綁定驗證碼點擊刷新事件#}
$('#id_img').click(function () {
var oldPath = $(this).attr('src');
$(this).attr('src',oldPath ='?')
});
{#發(fā)送ajax請求與后端交互#}
$('#id_submit').click(function () {
$.ajax({
url:'',
type:'post',
data:{
'username':$('#id_username').val(),
'password':$('#id_password').val(),
'code':$('#id_code').val(),
'csrfmiddlewaretoken':'{{ csrf_token }}'
},
{#進行處理后端數(shù)據(jù)#}
success:function (data) {
if(data.code==1000){
// 驗證成功則跳轉(zhuǎn)主頁
window.location.href = data.url
}else { // 報錯信息的展示
$('#id_error').text(data.msg)
}
}
})
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主頁</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
{#導(dǎo)航條樣式#}
<nav class="navbar navbar-inverse">
<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="/home/">BBS首頁系統(tǒng)</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 class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
{# 判斷用戶是否登錄 顯示登錄注冊按鈕#}
{% if request.user.is_authenticated %}
{# 根據(jù)后端,顯示登錄之后的按鈕#}
<li><a href="#">{{ request.user.username }}</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a>
<ul class="dropdown-menu">
{# 添加模態(tài)框的屬性data-toggle="modal" data-target="#myModal"#}
<li><a data-toggle="modal" data-target="#myModal">修改密碼</a></li>
<li><a href="#">修改頭像</a></li>
<li><a href="#">后臺管理</a></li>
<li role="separator" class="divider"></li>
<li><a href="{% url 'logout' %}">退出登錄</a></li>
</ul>
</li>
{% else %}
{# 沒有登錄則顯示登錄注冊按鈕#}
<li><a href="{% url 'login' %}">登錄</a></li>
<li><a href="{% url 'register' %}">注冊</a></li>
{% endif %}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{#整體頁面布局#}
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
{# 左邊面板#}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">點擊就送</h3>
</div>
<div class="panel-body">
勞斯萊斯5元代金券
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">限定優(yōu)惠</h3>
</div>
<div class="panel-body">
割雙眼皮買二送一
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading">
<h3 class="panel-title">最后換購</h3>
</div>
<div class="panel-body">
買電烤爐送蜂窩煤一斤!
</div>
</div>
</div>
{# 中間面板 #}
<div class="col-md-8"></div>
<div class="col-md-2">
{# 右邊面板#}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">點擊就送</h3>
</div>
<div class="panel-body">
勞斯萊斯5元代金券
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">限定優(yōu)惠</h3>
</div>
<div class="panel-body">
割雙眼皮買二送一
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading">
<h3 class="panel-title">最后換購</h3>
</div>
<div class="panel-body">
買電烤爐送蜂窩煤一斤!
</div>
</div>
</div>
</div>
</div>
{#修改密碼的彈出框#}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">修改密碼</h4>
</div>
<div class="modal-body">
{# 設(shè)置密碼的更改#}
<form action="{% url 'set_pwd' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="id_username">用戶名</label>
<input type="text" id="id_username" name="username" disabled class="form-control" value="{{ request.user.username }}">
</div>
<div class="form-group">
<label for="id_password">初始密碼</label>
<input type="password" id="id_password" name="old_password" class="form-control" >
</div>
<div class="form-group">
<label for="id_new_password">新密碼</label>
<input type="password" id="id_new_password" name="new_password" class="form-control" >
</div>
<div class="form-group">
<label for="id_confirm_password">確認(rèn)新密碼</label>
<input type="password" id="id_confirm_password" name="confirm_password" class="form-control">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button class="btn btn-primary" id="id_s">提交</button>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
1.定義登錄界面
2.添加驗證碼的功能
圖片驗證碼的傳值有三種方式,直接寫地址,文件二進制數(shù)據(jù),路徑
驗證碼的實現(xiàn)
通過Image獲取imgobj對象
生成好的img對象交給ImageDraw.Draw 生成畫筆
定義字體樣式,文字大小
產(chǎn)生隨機的驗證碼,利用chr實現(xiàn),(65,96)大寫,(97,122)小寫,數(shù)字直接就是0-9
隨機5個數(shù)字,在每個循環(huán)里寫入
利用畫筆對象.text((x軸,y軸)坐標(biāo),文本,圖片北京,字體樣式)
存儲寫的字
保存到session中的code
然后保存圖片io
最終返回給前端值 return HttpResponse(io_obj.getvalue())
3.給驗證碼綁定點擊事件
每點擊一次url添加一個?用于刷新
4.使用ajax與后端進行交互
將用戶的輸入獲取到手
success回調(diào)函數(shù)拿到后端返回的數(shù)據(jù)
根據(jù)code的信信息對相關(guān)標(biāo)簽進行渲染
后端得到數(shù)據(jù)進行驗證
先判斷驗證碼是否正確
然后利用auth模塊判斷密碼是否正確
根據(jù)得到對象判斷存在
定義返回字典,返回給前端
return JsonResponse(back_dic)
def get_code(request):
# 推導(dǎo)步驟一:直接發(fā)送后端存在的圖片
# img標(biāo)簽可以直接返回二進制數(shù)據(jù)進行顯示
# with open(r'static/img/02b02.jpg.jpg','rb') as f:
# data = f.read()
# return HttpResponse(data)
# 推導(dǎo)步驟二 利用pillow模塊自動生成圖片
'''
from PIL import Image,ImageDraw,ImageFont
Image 生成圖片
ImageDraw 在圖片上寫字
ImageFont 控制字體的樣式'''
# 生成圖片對象
# img_obj = Image.new('RGB',(360,35),'red') 直接放文件的顏色
# img_obj = Image.new('RGB',(360,35),get_random()) # 放rgb模式(255,23,232)
# # 利用文件操作先保存下來
# with open('xxx.png','wb') as f:
# img_obj.save(f,'png')
# # 然后利用文件操作將圖片數(shù)據(jù)讀取并發(fā)送
# with open(r'xxx.png','rb') as f:
# data = f.read()
# return HttpResponse(data)
# 推導(dǎo)步驟三 臨時存儲數(shù)據(jù)并且能夠隨時取出的地方
'''內(nèi)存管理模塊
from io import BytesIO,StringIO
BytesIO 保存數(shù)據(jù)(并且在獲取的時候,是以二進制的方式給你)
StringIO 保存數(shù)據(jù)(以字符串的形式給你)
'''
# img_obj = Image.new('RGB',(360,35),get_random())
# # # 先生成一個io對象
# # io_obj = BytesIO() # 可以將對象當(dāng)做是文件的句柄
# # # 存儲數(shù)據(jù)
# # img_obj.save(io_obj,'png')
# # # getvalue獲取二進制的數(shù)據(jù)
# # return HttpResponse(io_obj.getvalue())
# 推導(dǎo)步驟四 在圖片上寫字
img_obj = Image.new('RGB',(360,35),get_random())
# 將生成好的圖片對象交給imageDraw
img_draw = ImageDraw.Draw(img_obj) # 生成一個畫筆對象
# 字體樣式,將ttf格式字體,及字體的大小 設(shè)置
img_font = ImageFont.truetype('static/fonts/1.ttf',30)
# 產(chǎn)生一個隨機驗證碼 大小寫英文加數(shù)字 五位,每一位都可以是大小寫數(shù)據(jù)
code= ''
for i in range(5):
# chr 根據(jù)數(shù)字對應(yīng)字符編碼的英文
upper_str = chr(random.randint(65,90))
lower_str = chr(random.randint(97,122))
random_int = str(random.randint(0,9))
# 隨機選取一個字符
tmp = random.choice([upper_str,random_int,lower_str])
# 向圖片中寫入一個((x軸,y軸)坐標(biāo),文本,圖片北京,字體樣式)
img_draw.text((i*60 60,0),tmp,get_random(),img_font)
# 存儲寫的字
code = tmp
print(code)
# 這個驗證碼后面的其他視圖函可能用得上,找到地方保存,并且這個地方的全局視圖函數(shù)都可以訪問
request.session['code'] = code
# 圖片保存
io_obj = BytesIO()
img_obj.save(io_obj,'png')
return HttpResponse(io_obj.getvalue())