1.项目模块划分,目录结构搭建。
2.每个模块注册蓝图,并绑定。
#1.views.py注册蓝图
from flask import Blueprint
bp=Blueprint('cms',__name__,url_prefix='/cms')
@bp.route('/')
def index():
return "cms index"
#2.__init__.py导入蓝图
from .views import bp
#3.app.py绑定蓝图
from apps.cms import bp as cms_bp
app.register_blueprint(cms_bp)
3.数据库配置,连接,迁移控制。这里本来用了flask-script,但migrate的新版不支持他了,所以就不用script了。
#1.config.py文件中配置数据库信息
DEBUG=True
DB_USERNAME="root"
DB_PASSWORD="xxx"
DB_HOST="127.0.0.1"
DB_PORT="3306"
DB_NAME="bbs_cms"
DB_URI="mysql+pymysql://%s:%s@%s:%s/%s?charste='utf8" % (DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT,DB_NAME)
SQLALCHEMY_DATABASE_URI=DB_URI
SQLALCHEMY_TRACK_MODIFIER=False
#2.exts.py文件中导入sqlalchemy的实例化对象db
from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()
#3.在app.py文件中用flask-migrate管理数据库
from flask_migrate import Migrate
from exts import db
def create_app():
app=Flask(__name__)
app.config.from_object(config)
db.init_app(app)
app.register_blueprint(cms_bp)
app.register_blueprint(front_bp)
app.register_blueprint(common_bp)
migrate=Migrate(app,db)
return app
if __name__ =="__main__":
app=create_app()
app.run()
4.cms用户模型建立,并把模型映射到数据中
#1.models.py文件中建立模型
from exts import db
from datetime import datetime
class CMSUser(db.Model):
__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(50),nullable=False)
email=db.Column(db.String(50),nullable=False,unique=True)
join_time=db.Column(db.DateTime,default=datetime.now())
#2.模型导入到app.py文件中
from apps.cms import models
#3.在终端中进行映射三部曲
flask db init
flask db migrate
flask db upgrade
5.用命令行参数形式添加cms人员。
#1.在commands.py文件中定义命令行创建数据的函数
from apps.cms import models as cms_models
from exts import db
import click
CMSUser=cms_models.CMSUser
@click.option("-e","--email",required=True)
@click.option("-u","--username",required=True)
@click.option("-p","--password",required=True)
def create_cms_user(email,username,password):
user=CMSUser(username=username,email=email,password=password)
db.session.add(user)
db.session.commit()
print('cms用户添加成功')
#2.在app.py文件中导入并在create-app时,加入命令行函数
import commands
def create_app():
...
app.cli.command("add_cms_user")(commands.create_cms_user)
#3.命令行里面用参数添加数据
flask add_cms_user -e 18811752638@163.com -u zoe -p 111111
5.对数据库的密码保存经过加密
#在models,py文件里面对CMSUser模型重新定义,数据库内部用_password,但外部操作都用password,并进行hash加密解密
from exts import db
from datetime import datetime
from werkzeug.security import generate_password_hash,check_password_hash
class CMSUser(db.Model):
__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(200),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#讲一个方法变成属性,可属性方式访问,即user.password,返回的是self._password。
def password(self):
return self._password
@password.setter#定义了password的set方法,即user.password('abc'),将值传入
def password(self,raw_password):
self._password=generate_password_hash(raw_password)
def check_password(self,raw_password):
result=check_password_hash(self.password,raw_password)#这里的self.password调用了上面的函数,return self._password
return result
6.cms前端登录页面设计
get请求渲染
#1.在view里面创建视图类,并注册到蓝图
class LoginView(views.MethodView):
def get(self,message=None):
return render_template('cms/cms_login.html',message=message)
def post(self):
pass
bp.add_url_rule('/login/', view_func=LoginView.as_view('login'))
#2.cms_login.html,在bootstrap中文网,中文文档,入门,实例精选中找到符合自己的右键将html页面复制进去,然后修改:
<link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">#首先要引入bootstrap
<link rel="icon" href="{{url_for('static',filename='common/pic/bbs.ico')}}">#修改icon图片的地址
<link href="{{url_for('static',filename='cms/css/signin.css')}}" rel="stylesheet">#css样式的地址,和一些中文显示
{%if message %}#报错原因通过message拿到并渲染,当为None时,不渲染
<p class="alert alert-danger" style="text-align:center" role="alert">{{message}}</p>
{%endif%}
post表单提交
#1.在cms_login.html中修改提交方式为post,并对输入的内容添加name属性,后台会从name获取值
<form class="form-signin" method="post">
<input type="email" id="inputEmail" class="form-control" placeholder="邮箱" name="email" required autofocus>
<input type="password" id="inputPassword" class="form-control" placeholder="密码" name="password" required>
<input type="checkbox" value="1" name="remember"> 记住我
#2.表单提交之前需要在forms.py中对表单进行前端验证
from wtforms import Form,StringField,IntegerField
from wtforms.validators import Email,InputRequired,Length
class LoginForm(Form):
email=StringField(validators=[Email(message="请输入正确的邮箱格式"),InputRequired(message="请输入邮箱")])
password=StringField(validators=[InputRequired(message="请输入密码"),Length(6,20,message="密码长度不能小于6,大于20")])
remember=IntegerField()
#3.在views.py中导入表单验证form,并与后端数据库的数据进行比较处理,所以也要导入数据库模型文件model,并保留用户id到session中,
from .forms import LoginForm
from .models import CMSUser
import config
def post(self):
form=LoginForm(request.form)
if form.validate():
email=form.email.data
password=form.password.data
remeber=form.password.data
user=CMSUser.query.filter_by(email=email).first()#通过email找到用户
if user and user.check_password(password):
session[config.CMS_USER_ID]=user.id
if remeber :
session.permanent=True#保留31天
return redirect(url_for('cms.index'))
else:
return self.get(message="用户或密码错误")
else:
message=form.errors.popitem()[1][0]
return self.get(message=message)
#4.使用session一定要有key,所以在config文件中加入key,并且session中保留的user.id赋值给CMS_USER_ID
import os
SECRET_KEY=os.urandom(24)
CMS_USER_ID="NJNJNKJ"#任意给一个值
7.cms的首页登录限制,没有登录不可进入到cms的首页
#1.在decorates.py文件中,创建登录限制的装饰器,如果session中没有user_id就重定向到登录页面
from flask import session,redirect,url_for
from functools import wraps
import config
def login_required(func):
@wraps(func)
def inner(*args, **kwargs):
if config.CMS_USER_ID in session:
return func(*args, **kwargs)
else:
return redirect(url_for('cms.login'))
return inner
#2.在view.py文件中导入自定义的装饰器,然后放到给函数,这里路由装饰器一定要在其他装饰器前面
from .decorates import login_required
@bp.route('/')
@login_required
def index():
return "cms index"
8.cms的首页
#1.在17素材网等网站找前端网页模板,然后修改html里面js和css的地址,用url_for的方式导入,然后在view中render_template
<script src="{{url_for('static',filename='cms/js/cms_base.js')}}"></script>
#2.在_macros.html中将{{url_for('static',filename=“xx”}}抽象为宏
{% macro static(filename) -%}
{{url_for("static", filename=filename)}}
{%- wendmacro %}
#3.在cms_index.html中导入宏,并引入css和js文件
{%from "common/_macros.html" import static%}
<link rel="stylesheet" href="{{static('cms/css/cms_base.css')}}">
9.cms首页的user通过session中的user_id拿到user,绑到g上,然后在模板渲染时给出user_name;注销按钮取消session中user_id.
#1.在hooks.py文件中将现在登录的用户绑到g上
from .views import bp
from flask import session,g
import config
from .models import CMSUser
#钩子函数,befor_request:在每次请求之前执行
@bp.before_request
def before_request():
if config.CMS_USER_ID in session:
user_id =session.get(config.CMS_USER_ID)
user=CMSUser.query.get(user_id)
if user:#如果用户存在,就绑到g.cms_user
g.cms_user=user
#2.此时,这个钩子函数与app文件没有关联,因此不会执行,所以需要在__init__.py文件中导入
import apps.cms.hooks
#3.在cms_index.html文件中拿到g里面的user,并显示他的name
<li><a href="#">{{g.cms_user.username}}<span>[超级管理员]</span></a></li>
#4.在view.py文件中写注销函数
@bp.route('/logout/')
@login_required#先验证登录,登陆了才有注销功能,删掉session内容,再重定向到登录页面
def logout():
del session[config.CMS_USER_ID]
return redirect(url_for('cms.login'))
#5.在cms_index.html文件中对注销按钮的跳转函数写一下。
<li><a href="{{url_for('cms.logout')}}">注销</a></li>
9.cms模板抽离和个人信息页面
#1.将页面的共性内容抽离成父模板cms_base.html,子模版内容用{% block xxx%}{% endblock %}填充,子模版通过{% extends 'cms/cms_base.html' %}继承父模板,所以cms_profile.html可以如下
{% extends 'cms/cms_base.html' %}
{% block title %}
个人信息
{% endblock %}
{% block page_title %}
{% self.title() %}
{% endblock %}
#2.在views.py文件中写路由函数并渲染html
@bp.route('profile')
@login_required
def profile():
return render_template('cms/cms_profile.html')
#3.在cms_base.html中给个人信息href
<li><a href="{{url_for('cms.profile')}}">个人信息</a></li>