項目介紹
項目架子:
完成添加后台用戶功能
登錄的功能 基於flask_script ,因為說后台管理用戶,所以以命令的形式添加,不接受注冊。鞏固flask_script 在實際開發中的應用場景。
首先在models 中定義用戶表:
字段定義有:姓名,郵箱,密碼,簽名,用戶創建時間
1 #encoding:utf-8 2 from exts import db 3 from datetime import datetime 4 from werkzeug.security import generate_password_hash,check_password_hash 5 6 class User(db.Model): 7 __tablename__='user' 8 id=db.Column(db.Integer,primary_key=True,autoincrement=True) 9 name=db.Column(db.String(50),nullable=False) 10 email=db.Column(db.String(100),nullable=False,unique=True) 11 _passwd=db.Column(db.String(100),nullable=False) 12 # 簽名 13 autograph=db.Column(db.String(50)) 14 join_time=db.Column(db.DateTime,default=datetime.now) 15 16 def __init__(self,n,e,p,a): 17 self.name=n 18 self.email=e 19 self.passwd=p 20 self.autograph=a 21 22 @property 23 def passwd(self): 24 return self._passwd 25 26 @passwd.setter 27 def passwd(self,raw_pwd): # 用戶的密碼利用 generate_password_hash函數 加密。 28 self._passwd=generate_password_hash(raw_pwd) 29 30 def check_passwd(self,pwd): # 用戶密碼檢查,判斷輸入的密碼是否正確 31 return check_password_hash(self.passwd,pwd)
定義了實體模型之后,我們需要把類隱射到數據庫中,首先我們看程序主文件,PGpureLove.py
from flask import Flask from apps.home import home_bp from apps.admin import bp as admin_bp from exts import db,mail from flask_wtf import CSRFProtect import config def create_app(): # 定義工廠函數,創建app對象。 app = Flask(__name__) #Flaks方法 創建app對象 app.config.from_object(config) #綁定配置信息 app.register_blueprint(home_bp) #注冊藍圖 前台 app.register_blueprint(admin_bp) #注冊藍圖 后台 db.init_app(app) #讓app 應用程序使用這個數據庫設置 mail.init_app(app) #同上, 發送郵件時使用 CSRFProtect(app) return app if __name__ == '__main__': app=create_app() app.run()
app對象創建好之后,看下manage.py 文件:
#encoding:utf-8 from flask_script import Manager # 導入Manager 重要 必不可少。 from flask_migrate import Migrate,MigrateCommand # 做數據遷移用。 from PGpureLove import create_app #導入工廠函數 from exts import db #導入sqlalchemy 的實例對象 from apps.admin import models as admin_models #引入數據模型 AdminUser=admin_models.User #實例化 app=create_app() #創建一個app manager=Manager(app) #Manger綁定app Migrate(app,db) #綁定 app 與db manager.add_command('db',MigrateCommand) #MigrateCommand封裝了一套數據遷移的命令 @manager.option('-n','--name',dest='name') @manager.option('-p','--passwd',dest='passwd') @manager.option('-e','--email',dest='email') @manager.option('-a','--autograph',dest='autograph') def create_Admin(name,passwd,email,autograph): u=AdminUser(name,email,passwd,autograph) db.session.add(u) db.session.commit() print("<用戶已經創建>") if __name__=='__main__': manager.run()
在實際的開發環境中,經常會發生數據庫修改的行為。一般我們修改數據庫不會直接手動的去修改,而是去修改ORM對應的模型,然后再把模型映射到數據庫中。
flask-migrate是基於Alembic進行的一個封裝,並集成到Flask中,而所有的遷移操作其實都是Alembic做的,他能跟蹤模型的變化,並將變化映射到數據庫中。
1. 初始化一個環境:python manage.py db init
2. 自動檢測模型,生成遷移腳本:python manage.py db migrate
3. 將遷移腳本映射到數據庫中:python manage.py db upgrade
檢查表,已經創建了:
4. 更多命令:python manage.py db --help
完成一三步之后,就可以使用 create_Admin 創建后台賬號了。
查看數據庫
完成前台的登錄功能
后台登錄功能:
涉及flask 框架知識點: flask_script ,flask_migrate,藍圖,g對象,session,宏,flask_wtf
首先設計前台登錄頁面,頁面是網上找的:
首先定義一個宏。
登錄界面:
{% from 'comm/_maro.html' import static %} // 導入宏 <!DOCTYPE html> <div class="animate form login_form"> <section class="login_content"> <form method="post"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <h1>登錄</h1> <div> <input name="username" type="text" class="form-control" placeholder="郵箱號" required=""> </div> <div> <input name="password" type="password" class="form-control" placeholder="密碼" required=""> {% if message %} <p style="text-align: center" class="text-danger">{{ message }}</p> {% endif %} </div> <div class="checkbox3 checkbox-success checkbox-inline checkbox-check checkbox-round checkbox-light"> <input name="remember" value="1" type="checkbox" id="checkbox-fa-light-1" checked=""> <label for="checkbox-fa-light-1"> 記住密碼 </label> </div> <div> <button class="btn btn-default submit" type="submit">登錄</button> <a class="reset_pass" href="#">您的密碼丟失?</a> </div> <div class="clearfix"></div> <div class="separator"> <p class="change_link">第一次訪問網站? <a href="http://demo.cssmoban.com/cssthemes4/cttp_1_gentelella/production/login.html#signup" class="to_register"> 注冊賬戶 </a> </p> <div class="clearfix"> </div> <br> <div> <p>©2016 All Rights Reserved. Gentelella Alela! is a Bootstrap 3 template. Privacy and Terms</p> </div> </div> </form> </section> </div>
這時候 需要創建 form.py 創建
from wtforms import Form class BaseForm(Form): def get_error(self): return self.errors.items()[1][0]
from apps.forms import BaseForm from wtforms import StringField,IntegerField,PasswordField from wtforms.validators import Required,Email,EqualTo,Length,InputRequired from flask import g from utils import cacheLib class LoginForm(BaseForm): username=StringField(validators=[Email(message='郵箱格式不正確'),InputRequired(message='請輸入郵箱')]) password=StringField(validators=[InputRequired(message='請輸入密碼'),Length(6,50,message='密碼長度只能6-50')]) remember=IntegerField()
完成之后 ,我們需要定義個一視圖來渲染login.html 頁面,進入views.py 中。
from flask import Blueprint,render_template,request,g,session,redirect,url_for
from .forms import LoginForm,RestPwdForm
from flask import views,render_template
from .models import User
from .decorators import login_requid
import config
from exts import db
bp=Blueprint('admin',__name__,url_prefix='/admin')
# 登錄功能 基於調度方法的視圖 class LoginView(views.MethodView): #需要繼承 MethodView方法 def get(self,message=None): #get 請求登錄頁面 return render_template('comm/login.html',message=message) def post(self): #處理用戶提交的登錄信息 form=LoginForm(request.form) # 處理表單提交的數據 傳遞 request.form if form.validate(): # 如果驗證通過。 name=form.username.data #獲取用戶名 pwd=form.password.data #獲取密碼 remb=form.remember.data #獲取記住密碼 user=User.query.filter_by(email=name).first() #通過flask_sqlalchemy 查詢該用戶。 if user and user.check_passwd(pwd) : #檢查輸入的密碼對不對,內部調用的check_password_hash方法,如果有這個用戶 並且密碼對的 session[config.CMS_USER_ID]=user.id # 首先把用戶di傳到seesion中 if remb: session.permanent=True return redirect(url_for('admin.index')) else: return self.get(message='密碼錯誤') else: return "驗證不通過" bp.add_url_rule('/login/',view_func=LoginView.as_view('login'))
登錄功能完成, 我們需要測試幾種場景:
表單驗證的信息
1 密碼輸入正確的時候,登錄正常
2 直接點登錄:
用戶名 密碼都會有提示,
但是這只說前端的驗證,后台我們同樣是要去處理這種異常情況。
3 用戶名或密碼輸入錯誤
建議不要提示太明顯,以前做測試的時候要求開發提示清晰,讓用戶知道自己說用戶名或者密碼輸錯了。
但這樣也不安全。活躍的用戶是不可能把賬號都忘掉的。
因為沒有使用ajax ,http是無狀態的,當輸入錯誤的郵箱或者密碼,我們想在表單中保留上次輸入的數據,這就需要在把數據回傳到render_templete 函數中。
4 登錄成功,正常跳轉到首頁。
5 當用戶在登錄之后,我們需要驗證session。
這些頁面都說要登錄之后才能看到的。所以我們現在要來實現這個裝飾器。
from flask import session,redirect,url_for from functools import wraps # 避免在使用的過程 from config import CMS_USER_ID def login_requid(func): @wraps(func) def warp(*args,**kwargs): if CMS_USER_ID in session: return func(*args,**kwargs) else: return redirect(url_for('admin.login')) return warp
之后 只要在需要的地方引入即可。