項目搭建
創建一個項目之后,需要在手動創建幾個包(含有__init__.py文件的目錄)和文件
1、在主目錄下創建配置文件:config.py
2、在主目錄下創建擴展文件:exts.py
3、在主目錄下創建管理文件(供在命令行使用):manage.py
4、在主目錄下創建app包,在app包下再創建cms包管理后台的文件
5、在cms包下創建views.py文件管理視圖函數、models.py文件管理數據庫模型、forms.py文件管理表單驗證
填寫配置文件
在配置文件下配置密鑰、數據庫連接等(配置文件的所有變量必須是全部大寫)
主目錄/config.py import os SECRET_KEY = os.urandom(24) DEBUG = True SQLALCHEMY_DATABASE_URI = "mysql://你的數據庫用戶名:用戶密碼@127.0.0.1:3306/數據庫名稱" SQLALCHEMY_TRACK_MODIFICATIONS = False
填寫擴展文件
Flask框架封裝了數據庫的一些操作,將其置為擴展包falsk-sqlalchemy,只需要實例化SQLAlchemy對象
主目錄/exts.py from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy()
創建應用app
在入口文件定義一個創建app的方法,供藍圖使用,這里說的藍圖就是app包下的包(模塊).由於本篇博客實現的是后台登錄,即涉及表單驗證,所以需要防止csrf注入攻擊
主目錄/app.py from flask import Flask from flask_wtf import CSRFProtect from apps.cms import bp as cms_bp from apps.cms import login_manager as cms_login_manager import config from exts import db def create_app(): """ 主入口文件創建app,供其他藍圖使用 :return: 返回一個app """ app = Flask(__name__) # 防止csrf注入攻擊 CSRFProtect(app) # 注冊藍圖模塊 app.register_blueprint(cms_bp, url_prefix="/cms") # 導入配置文件 app.config.from_object(config) # 數據庫db初始化app db.init_app(app) # 后台登錄login_manager初始化app cms_login_manager.init_app(app) return app if __name__ == '__main__': app = create_app() app.run()
初始化藍圖
cms包下有一個初始化py文件,一般是用來供導包的
主目錄/app/cms/__init__.py from .views import bp from .views import login_manager
創建用戶模型
在藍圖中的模型文件中創建用戶模型,即在cms包下的models.py文件創建。創建模型已作詳細說明
主目錄/app/cms/models.py from exts import db from datetime import datetime from werkzeug.security import generate_password_hash, check_password_hash from flask_login import UserMixin class CMSUser(db.Model, UserMixin): """ 定義一個類名,系統將類轉換為表格,表名為cms_user 定義類的屬性就是表格的字段名 為了安全性,可以將用戶表的password屬性置為保護屬性如 _password 為了方便用戶操作保護屬性像操作普通屬性一樣,需要裝飾 _password 在設置密碼的過程中,需要對密碼加密——>調用generate_password_hash() 另外定義一個校驗密碼的方法check_password() 在校驗密碼的過程中,需要對密碼解密——>調用check_password_hash() """ __tablename__ = "cms_user" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(50), nullable=False) _password = db.Column(db.String(100), nullable=False) email = db.Column(db.String(50), nullable=False, unique=True) join_time = db.Column(db.DateTime, default=datetime.now) def __init__(self, username, password, email): self.username = username self.password = password self.email = email @property def password(self): return self._password @password.setter def password(self, raw_password): """ 設置密碼 :param raw_password: 前端后台傳入的密碼參數 :return:沒有返回值 """ self._password = generate_password_hash(raw_password) def check_password(self, raw_password): """ 校驗密碼,將數據庫的存入的密碼解密之后再與傳入的密碼參數匹配 :param raw_password: 前端后台傳入的密碼參數 :return: True or False """ result = check_password_hash(self.password, raw_password) return result
遷移並同步到數據庫中
Flask框架不像Django框架可以直接使用命令行生成遷移文件並同步到數據庫當中,Flask框架需要借助flask_script包下的管理類Manager、flask_migrate包下的遷移類Migrate和一些相關的遷移命令類MigrateCommand。
1、先獲取app對象
2、再實例化一個管理對象manage,綁定到app上
3、將app應用與db數據庫對象綁定到遷移類中
4、將遷移文件中用到的命令封裝成 db (這個db不是db數據庫對象),調用add_command()添加到manage中
5、完成上面幾個文件的代碼填充,可以在命令行中輸入相關命令,這里不做解釋,代碼中有提示
主目錄/manage.py from flask_script import Manager from flask_migrate import Migrate, MigrateCommand from app import create_app from exts import db from apps.cms import models as cms_models # 獲取模型中定義的類 CMSUser = cms_models.CMSUser app = create_app() # 定義Manager類實例化對象 manage = Manager(app) # 將app應用與db數據庫綁定到遷移文件中 Migrate(app, db) # 將遷移文件用到的命令換成db開頭(manage.py文件可以自定義命令)添加到manage中 manage.add_command("db", MigrateCommand) @manage.option("-u", "--username", dest="username") @manage.option("-p", "--password", dest="password") @manage.option("-e", "--email", dest="email") def create_cms_user(username, password, email): """ 自定義創建后台用戶的命令,在cmd命令行中輸入類似於如下命令,即可添加用戶:(在虛擬環境下) python manage.py db create_cms_user -u 用戶名 -p 密碼 -e 郵箱地址 :param username: :param password: :param email: :return: 返回一提示消息 """ user = CMSUser(username=username, password=password, email=email) db.session.add(user) db.session.commit() print("cms用戶添加成功") if __name__ == "__main__": manage.run()
表單驗證
對前端后台登錄的表單提供的數據進行驗證,需要借助flask_wtf包下的FlaskForm類
主目錄/app/cms/forms.py from flask_wtf import FlaskForm from wtforms import StringField, IntegerField from wtforms.validators import DataRequired, Length, Email class LoginForm(FlaskForm): email = StringField(validators=[DataRequired(message="請輸入郵箱地址"), Email(message="請輸入正確的郵箱格式")]) password = StringField(validators=[Length(6, 20, message="請輸入正確格式的密碼")]) remember = IntegerField()
渲染頁面
這里沒有設置頁面,就不渲染頁面,直接返回一個字符串標識一下即可。渲染頁面做的事情一般是在views.py中實現的,這個views.py文件采用了兩種方式:視圖函數和基於調度方法的類視圖。
這里有必要提一下:對於沒有登錄的行為,是不能訪問主頁(這里是指登錄成功之后跳轉的頁面)。實現這一要求,我們需要從flask_login包下導入login_user、logout_user、login_required、LoginManager
1、和上面一樣,實例化LoginManager對象login_manager也要初始化app(在入口文件app.py會有一行代碼)
2、對於沒有登錄的用戶我們需要給一個重定向(我們把它作為重定向)。這個實例化對象有一個屬性login_view,給其賦值(值是一個url)
3、最重要的一點:調用了login_user()會自動生成一個session值,調用了logout_user()會自動刪除這一個session值。這個session值是通過裝飾器@login_manager.user_loader修飾的函數生成
4、視圖函數和類視圖已在代碼中作詳細說明
主目錄/app/cms/views.py from flask import Blueprint, views, render_template, request, session, redirect, url_for from flask_login import login_required, LoginManager from flask_login import login_user from .forms import LoginForm from .models import CMSUser # 指定沒有登錄時重定向的頁面,需要將LoginManager的實例化對象初始化app(在入口文件中) login_manager = LoginManager() login_manager.login_view = "cms.login" # 定義藍圖對象 bp = Blueprint("cms", __name__) @bp.route("/") @login_required def index(): return "cms index" class LoginView(views.MethodView): """ get方法對應前端后台的get請求,主要是渲染頁面 post方法對應前端后台的post請求: 1、先驗證用戶的輸入是否符合表單驗證的要求,如果不符合要求,則返回具體的錯誤 2、先通過郵箱查找用戶並通過查找的用戶密碼與后台表格密碼進行驗證,如果沒有找到,返回郵箱或者密碼錯誤 3、匹配成功則通過login_user(user)自動保存session值 4、通過獲取前端后台的remember值給session定義過期時間,默認是瀏覽器會話關閉 """ def get(self, message=None): return render_template("cms/cms_login.html", message=message) def post(self): form = LoginForm(request.form) if form.validate(): email = form.email.data password = form.password.data remember = form.remember.data user = CMSUser.query.filter(CMSUser.email == email).first() if user and user.check_password(password): # 自動生成一個session值 login_user(user) if remember: # 設置session的過期時間,默認為31天 session.permanent = True return redirect(url_for("cms.index")) return redirect(url_for("cms.index")) else: return self.get(message="郵箱或者密碼錯誤") else: message = form.errors.popitem()[1][0] return self.get(message=message) bp.add_url_rule("/login", view_func=LoginView.as_view("login")) @login_manager.user_loader def load_user(user_id): """ 后台用戶類必須繼承UserMixin,以防用戶表沒有定義校驗的字段,如:is_active等 :param user_id: :return: """ return CMSUser.query.get(user_id)
前台用當前登錄的用戶的相關信息的幾種方式:
1、可以在模板上(頁面)使用當前登陸用戶的代理current_user(具體值就加“點屬性”)
2、在views.py文件中將登錄的用戶信息保存到 g 對象中(這個 g 對象很重要,而且使用很方便)
這樣一個后台登錄實現已經實現了,能幫助到大家,點個贊,加個關注,誠摯感謝!