赞
踩
一。配置文件
代码命令:
视图函数:
env = get_env()
config = configs[env]
app.config.from_object(config)
config.init_app(app)
配置文件(config.py):
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = 'Chapter6'
SQLALCHEMY_TRACK_MODIFICATIONS = False
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
configs = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
}
效果图:
操作步骤:
首先在pychram的终端输入:
操作代码命令:
Set FLASK_ENV=development
然后在pychram上找到“运行\配置调试”,并点击;
在“运行\配置调试”界面中,点击“编辑配置”;
在“编辑配置”界面中,点击“添加新配置”;
在“添加新配置”界面中点击“Flask 服务器”;
在新建的flask服务器界面中,找到flask环境,将其改为指定内容;
改正内容:testing
常见问题:
暂无。
注意事项:
暂无。
二。项目结构
应用管理入口
代码命令:
应用管理入口模板文件(manage.py):
from flask.helpers import get_env
from flask_migrate import MigrateCommand
from flask_script import Manager, Shell
from app import create_app, db, dh
from app.commands import register_manage_commands
# 根据相应的环境创建应用实例,并初始化 Manager
env = get_env()
app = create_app(env)
manager = Manager(app)
def make_shell_context():
context = dict(
db=db,
dh=dh,
)
# 将所有模型注册到交互 Shell
context.update((cls.__name__, cls) for cls in dh.get_all_model_classes())
return context
# 注册指令到 Manager
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
register_manage_commands(manager)
if __name__ == '__main__':
manager.run()
应用“工厂”函数
代码命令:
应用“工厂”函数(app\__init__.py)代码:
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_login import LoginManager
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from config import configs
from .database import DatabaseHelper
from .errors import register_app_errors
# 对象在函数外创建,以便于在其它文件中引用。
bootstrap = Bootstrap()
db = SQLAlchemy()
migrate: Migrate
login_manager = LoginManager()
# 创建数据库助手类实例
dh = DatabaseHelper(db)
# 将创建应用的流程封装成函数,便于管理。
def create_app(env):
app = Flask(__name__)
# 加载应用配置
config = configs.get(env)
app.config.from_object(config)
config.init_app(app)
# 初始化数据库操作实例
db.init_app(app)
# 初始化 Flask-Migrate
global migrate
migrate = Migrate(app, db)
migrate.init_app(app, render_as_batch=True)
# 初始化 Flask-BootStrap
bootstrap.init_app(app)
bootstrap_cdns = app.extensions['bootstrap']['cdns']
bootstrap_cdns['bootstrap'] = bootstrap_cdns['local']
bootstrap_cdns['jquery'] = bootstrap_cdns['local']
# 初始化 Flask-Login
login_manager.login_view = 'user.login'
login_manager.login_message_category = 'danger'
login_manager.login_message = '请登录后再进行操作'
login_manager.init_app(app)
# 将各模块的蓝图(Blueprint)注册到应用实例
from .user import user
# url_prefix参数可以为用户模块添加上级位置
app.register_blueprint(user, url_prefix='/user')
from .admin import admin, admin_user
app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(admin_user, url_prefix='/admin/user')
from .portal import portal
app.register_blueprint(portal)
# 将所有模型类注册到模板全局变量,以便于后续调用
# 注册模型须放置在所有模型加载之后,否则将获取不到相应模型
for cls in dh.get_all_model_classes():
app.add_template_global(cls)
# 注册应用错误视图
register_app_errors(app)
return app
数据库(app\database.py)代码:
from flask_sqlalchemy import BaseQuery, Model, SQLAlchemy
# 定义所有模型的基类
from sqlalchemy.orm import Session
class BaseModel(Model):
# 声明 query 属性的类型,以获得代码提示补全
query: BaseQuery
# 定义模型初始化方法
def __init__(self, **kwargs):
# 将参数传入父类初始化方法
super(BaseModel, self).__init__(**kwargs)
# 定义对象输出格式,方便输出预览
def __repr__(self):
fields = []
# 获取对象原始数据
for k, v in self.__dict__.items():
# 只输出相关属性
if k[0] != '_':
# 防止模型关联后无限递归
if isinstance(v, BaseModel):
fields.append('%s=<%s ...>' % (k, v.__class__.__name__))
elif isinstance(v, str):
fields.append("%s='%s'" % (k, v))
else:
fields.append('%s=%a' % (k, v))
# 拼接显示结果
result = '<%s %s>' % (self.__class__.__name__, ' '.join(fields))
return result
# 定义数据库助手类,以便于进行一些常用操作
class DatabaseHelper:
def __init__(self, db: SQLAlchemy):
self._db = db
# 获取所有基于 BaseModel 类的模型,以便于注册到交互 Shell。
def get_all_model_classes(self):
classes = []
for cls in self._db.Model._decl_class_registry.values():
if hasattr(cls, '__tablename__') and issubclass(cls, BaseModel):
classes.append(cls)
return classes
# 定义获取 db.session 的属性,以获得完整的代码补全
@property
def session(self) -> Session:
return self._db.session
常见问题:
ModuleNotFoundError: No module named 'flask_login'
问题原因:
因为在其Python 环境中没有安装 flask_login 这个模块。
解决方法:
pip install Flask-Login
ImportError: cannot import name 'BaseResponse' from 'werkzeug.wrappers'
问题原因:
这个错误指从 werkzeug.wrappers 模块中导入 BaseResponse 类,但是在该模块中找不到这个名称。
解决方法:
pip install Werkzeug==2.0.3
ImportError: cannot import name 'url_encode' from 'werkzeug'
问题原因:
这个错误指在werkzeug的当前版本过高。
解决方法:
pip install Werkzeug==0.16.0
注意事项:
暂无。
三。模块化开发
使用蓝图
代码命令:
蓝图初始化(app/user/__init__.py):
from flask import Blueprint
user = Blueprint('user', __name__)
# 加载相关的模型、视图、错误视图、公共方法
from . import models, views, errors, common
数据模型(app/user/models.py):
from flask_login import UserMixin
from app import db
from app.database import BaseModel
# 使用户模型继承 Flask-Login 的标准用户实现(UserMixin)
class UserModel(UserMixin, db.Model, BaseModel):
__tablename__ = 'user'
id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
username = db.Column(db.VARCHAR, unique=True)
password = db.Column(db.VARCHAR)
is_admin = db.Column(db.BOOLEAN, default=False, nullable=False)
info = db.relationship('UserInfoModel', backref='user', uselist=False, cascade='all')
class UserInfoModel(db.Model, BaseModel):
__tablename__ = 'user_info'
user: UserModel
user_id = db.Column(db.INTEGER, db.ForeignKey(UserModel.id), primary_key=True)
phone = db.Column(db.VARCHAR)
email = db.Column(db.VARCHAR)
introduce = db.Column(db.TEXT)
表单模型(app/user/forms.py):
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, TextAreaField, BooleanField
from wtforms.validators import DataRequired, Email, Optional, Regexp
class LoginForm(FlaskForm):
username = StringField(label='用户名', validators=[DataRequired()])
password = PasswordField(label='密码', validators=[DataRequired()])
remember = BooleanField(label='记住该用户')
submit = SubmitField(label='登录')
class RegisterForm(FlaskForm):
username = StringField(label='用户名', validators=[DataRequired()])
password = PasswordField(label='密码', validators=[DataRequired()])
# 此处使用 11位数字 的正则表达式检测手机号
phone = StringField(label='手机号', validators=[Optional(), Regexp(r'\d{11}')])
email = StringField(label='邮箱', validators=[Optional(), Email()])
introduce = TextAreaField(label='自我介绍')
submit = SubmitField(label='注册')
视图函数模型(app/user/views.py):
from flask import render_template, request, redirect, flash, abort
from flask_login import login_user, logout_user, login_required
from app import dh
from . import user
from .common import get_current_user
from .forms import *
from .models import *
# 用户注册
@user.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
if request.method == 'POST' and form.validate_on_submit():
item = UserModel(
username=form.username.data,
password=form.password.data,
info=UserInfoModel(
phone=form.phone.data,
email=form.email.data,
introduce=form.introduce.data,
),
)
try:
dh.session.add(item)
dh.session.commit()
flash('注册成功', 'success')
return redirect('login')
except Exception as e:
flash('注册失败 - %s' % e, 'danger')
return abort(500)
else:
return render_template('user/register.html', form=form)
# 用户登录
@user.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST' and form.validate_on_submit():
try:
item = UserModel.query.filter_by(username=form.username.data, password=form.password.data).first()
if item is not None:
# 使用Flask-Login完成用户登录认证
login_user(item)
flash('登录成功', 'success')
return redirect(request.path)
else:
raise Exception('用户名或密码错误')
except Exception as e:
flash('登录失败 - %s' % e, 'danger')
return abort(500)
else:
return render_template('user/login.html', form=form)
# 查看用户信息
@user.route('/<int:id>')
def view(id: int):
try:
item = UserModel.query.get(id) # type: UserModel
if item is not None:
return render_template('user/view.html', item=item)
else:
raise Exception('用户不存在')
except Exception as e:
flash('查看用户 - %s' % e, 'danger')
return abort(404)
@user.route('/logout')
@login_required
def logout():
if logout_user():
flash('注销成功', 'success')
return redirect('/user/login')
# 查看用户信息(当前用户)
@user.route('/')
@login_required
def view_current():
item = get_current_user()
return render_template('user/view.html', item=item)
“工厂”函数模型(app/__init__.py)修改的代码部分:(已改)
# 将各模块的蓝图(Blueprint)注册到应用实例
from .user import user
# url_prefix参数可以为用户模块添加上级位置
app.register_blueprint(user, url_prefix='/user')
操作步骤:
首先在打开pychram的终端;
在终端中输入指定运行的环境代码指令;
代码命令:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> set FLASK_ENV='development'
然后输入生成数据库的代码指令;
代码命令:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> python manage.py db init
仍然在终端中输入更新数据库结构的代码指令;
代码命令:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> python manage.py db migrate
还是在终端中输入用于匹配数据库迁移版本的代码指令;
代码命令:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> python manage.py db upgrade
最后在终端中输入执行应用管理入口文件(manage.py)文件的代码指令;
代码命令:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> python manage.py runserver
效果图:
用户注册界面
用户登录界面
查看用户信息界面
子模块
代码命令:
管理模块(admin/__init__.py)初始化:
from flask import Blueprint
admin = Blueprint('admin', __name__)
from .user import user as admin_user
from . import views
用户管理模块(admin/user/__init__.py)初始化:
from flask import Blueprint
user = Blueprint('admin.user', __name__)
from . import views, errors
“工厂”函数(app/__init__.py)添加的代码部分:(已添加)
# 将各模块的蓝图(Blueprint)注册到应用实例
from .user import user
# url_prefix参数可以为用户模块添加上级位置
app.register_blueprint(user, url_prefix='/user')
from .admin import admin, admin_user
app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(admin_user, url_prefix='/admin/user')
from .portal import portal
app.register_blueprint(portal)
效果图:
后台界面
用户管理功能
常见问题:
Error: Directory migrations already exists and is not empty
问题原因:
数据库以存在,但没有及时更新。
解决方法:
将删除migrations文件夹,及创建的数据库,然后重新执行一遍操作步骤的对应命令。
注意事项:
注册用户前先要检查数据库是否存在,且是否可以正常使用。
四。Flask-Login
代码命令:
应用初始化文件(app/__init__.py)添加的代码部分:(已添加)
# 初始化 Flask-Login
login_manager.login_view = 'user.login'
login_manager.login_message_category = 'danger'
login_manager.login_message = '请登录后再进行操作'
login_manager.init_app(app)
用户模型()添加继承Flask-Login的代码部分:(已添加)
class UserModel(UserMixin, db.Model, BaseModel):
__tablename__ = 'user'
id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
username = db.Column(db.VARCHAR, unique=True)
password = db.Column(db.VARCHAR)
is_admin = db.Column(db.BOOLEAN, default=False, nullable=False)
info = db.relationship('UserInfoModel', backref='user', uselist=False, cascade='all')
公共方法模块(user/common.py)添加用户加载器的代码部分:
from flask_login import current_user
from app import login_manager
# 用于 Flask-Login 获取用户
from .models import UserModel
@login_manager.user_loader
def _load_user(id: int):
return UserModel.query.get(id)
# 获取当前用户,指定类型以便于获取代码补全
def get_current_user() -> UserModel:
return current_user
视图函数(user/views.py):
from flask_login import login_user, logout_user, login_required
# 用户登录
@user.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST' and form.validate_on_submit():
try:
item = UserModel.query.filter_by(username=form.username.data, password=form.password.data).first()
if item is not None:
# 使用Flask-Login完成用户登录认证
login_user(item)
flash('登录成功', 'success')
return redirect(request.path)
else:
raise Exception('用户名或密码错误')
except Exception as e:
flash('登录失败 - %s' % e, 'danger')
return abort(500)
else:
return render_template('user/login.html', form=form)
要求认证访问
代码命令:
视图函数(user/views.py):
from flask_login import login_user, logout_user, login_required
from .common import get_current_user
@user.route('/logout')
@login_required
def logout():
if logout_user():
flash('注销成功', 'success')
return redirect('/user/login')
# 查看用户信息(当前用户)
@user.route('/')
@login_required
def view_current():
item = get_current_user()
return render_template('user/view.html', item=item)
查看用户登录信息模板(app/templates/common/nav.html):
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<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="/">模块化开发</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="true">
后台管理
<span class="caret"></span></a>
<ul class="dropdown-menu">
{# <li><a href="{{ url_for('admin.index') }}">后台首页</a></li>#}
{# <li><a href="{{ url_for('admin.user.index') }}">用户管理</a></li>#}
<li><a>后台首页</a></li>
<li><a>用户管理</a></li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
{% if current_user.is_anonymous %}
{# 如果用户没有登录,即显示游客用的菜单 #}
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="true">
游客
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ url_for('user.login') }}">登录</a></li>
<li><a href="{{ url_for('user.register') }}">注册</a></li>
</ul>
{% else %}
{# 登录以后显示用户名 #}
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="true">
{{ current_user.info.nickname or current_user.username }}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ url_for('user.view_current') }}">用户信息</a></li>
<li class="divider"></li>
<li><a href="{{ url_for('user.logout') }}">注销</a></li>
</ul>
{% endif %}
</li>
</ul>
</div>
</div>
</nav>
效果图:
查看当前登录用户信息的效果
注销用户后,查看当前登录用户信息的效果
管理员认证访问
代码命令:
“admin_required”装饰器(admin/common.py):
from functools import wraps
from flask import abort, flash
from flask_login import login_required
from app.user.common import get_current_user
def admin_required(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if not get_current_user().is_admin:
flash('拒绝访问', 'danger')
return abort(403)
return func(*args, **kwargs)
return login_required(decorated_view)
后台首页(admin/views.py):
from flask import render_template
from . import admin
from .common import admin_required
@admin.route('/')
@admin_required
def index():
return render_template('admin/index.html')
效果图:
普通用户访问后台
管理员用户访问后台
操作步骤:
首先创建一个名为“admin”的用户;
然后在pychram的终端中输入代码指令;
代码命令:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> python manage.py shell
再然后在打开的shell命令框中输入代码指令;
代码命令:
>>> admin = UserModel.query.filter_by(username='admin').first()
>>> admin.is_admin = True
>>> db.session.add(admin)
>>> db.session.commit()
>>> exit()
最后重新进入浏览器中访问“http://127.0.0.1:5000/admin/”即可。
常见问题:
暂无。
注意事项:
需要先建一个名为“admin”的用户,不然无法指定“admin”用户为管理员用户。
五。管理员注册
代码命令:
管理指令(app/commands.py):
from flask_script import Manager
from app import dh
from app.user.models import UserModel, UserInfoModel
def register_manage_commands(manager: Manager):
@manager.command
def create_admin():
username = input('Input Username:')
password = input('Input Password:')
item = UserModel(username=username, password=password, is_admin=True,
info=UserInfoModel(introduce='Create By Manager.'))
dh.session.add(item)
dh.session.commit()
应用管理入口(manage.py):
from flask.helpers import get_env
from flask_migrate import MigrateCommand
from flask_script import Manager, Shell
from app import create_app, db, dh
from app.commands import register_manage_commands
# 根据相应的环境创建应用实例,并初始化 Manager
env = get_env()
app = create_app(env)
manager = Manager(app)
def make_shell_context():
context = dict(
db=db,
dh=dh,
)
# 将所有模型注册到交互 Shell
context.update((cls.__name__, cls) for cls in dh.get_all_model_classes())
return context
# 注册指令到 Manager
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
register_manage_commands(manager)
if __name__ == '__main__':
manager.run()
效果图:
执行代码:
(.venv) PS C:\Users\钟离\PycharmProjects\flaskProject1> python manage.py create_admin
使用Manager注册管理员
常见问题:
暂无。
注意事项:
暂无。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。