网站少不了要和数据库打交道,归根到底都是一些增删改查操作,这里做一个简单的用户登录功能来学习一下Flask如何操作MySQL。


用到的一些知识点:Flask-SQLAlchemy、Flask-Login、Flask-WTF、PyMySQL

这里通过一个完整的登录实例来介绍,程序已经成功运行,在未登录时拦截了success.html页面跳转到登录页面,登录成功后才能访问success。

以下是项目的整体结构图:

首先是配置信息,配置了数据库连接等基本的信息,config.py

DEBUG = True
SQLALCHEMY_ECHO = False
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:1011@localhost/rl_project?charset=utf8'
SECRET_KEY = '*\xff\x93\xc8w\x13\x0e@3\xd6\x82\x0f\x84\x18\xe7\xd9\\|\x04e\xb9(\xfd\xc3'

  

common/_init_.py

# config=utf-8
from flask_sqlalchemy import SQLAlchemy __all__ = ['db']
db = SQLAlchemy()

  

数据库配置类,common/data.py

# config=utf-8
from sqlalchemy import create_engine
from sqlalchemy.sql import text
from config import SQLALCHEMY_DATABASE_URI, SQLALCHEMY_ECHO def db_query(sql, settings=None, echo=None): if settings is None:
settings = SQLALCHEMY_DATABASE_URI if echo is None:
echo = SQLALCHEMY_ECHO return create_engine(settings, echo=echo).connect().execute(text(sql)).fetchall() def db_execute(sql, settings=None, echo=None): if settings is None:
settings = SQLALCHEMY_DATABASE_URI if echo is None:
echo = SQLALCHEMY_ECHO return create_engine(settings, echo=echo).connect().execute(text(sql)).rowcount

  

SQLALCHEMY_DATABASE_URI用于连接数据的数据库。
SQLALCHEMY_ECHO如果设置成 True,SQLAlchemy 将会记录所有 发到标准输出(stderr)的语句,这对调试很有帮助。
当然,我们在setting中设置了基本的连接数据库信息,启动时加载app = create_app('../config.py'),所以这个类删掉也不会报错。

form/login_form.py

# config=utf-8
from flask_wtf import FlaskForm as Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired class LoginForm(Form):
accountNumber = StringField('accountNumber', validators=[DataRequired('accountNumber is null')])
password = PasswordField('password', validators=[DataRequired('password is null')])

  

使用Flask-WTF做登录的表单验证,这里简单做了账号密码不为空
 
如,当我们不填写密码时,点击登录:

model/_init_.py

# config=utf-8
from flask import Flask
from flask_login import LoginManager
from common import db login_manager = LoginManager()
login_manager.login_view = "user.login" def create_app(config_filename=None):
app = Flask(__name__)
login_manager.init_app(app) if config_filename is not None:
app.config.from_pyfile(config_filename)
configure_database(app) return app def configure_database(app):
db.init_app(app)

  

其中,login_manager.login_view = "user.login" 指定了未登录时跳转的页面,即被拦截后统一跳到user/login这个路由下
 
model/user_model.py
# config=utf-8
from flask_login import UserMixin
from common import db class User(db.Model, UserMixin): user_id = db.Column('id', db.Integer, primary_key=True)
accountNumber = db.Column(db.String(200), unique=True)
password = db.Column(db.String(50), unique=True)
name = db.Column(db.String(20), unique=True) __tablename__ = 'tb_user' def __init__(self, user_id=None, account_number=None, password=None, name="anonymous"): self.user_id = user_id
self.accountNumber = account_number
self.password = password
self.name = name def is_authenticated(self):
return True def is_active(self):
return True def is_anonymous(self):
return False def get_id(self):
return unicode(self.user_id) def __repr__(self):
return '<User %r>' % (self.accountNumber)

  

这里需要注意:

def get_id(self):
return unicode(self.user_id)
该方法不可缺少,否则会报:NotImplementedError: No `id` attribute - override `get_id`错误。
 
get_id()
返回一个能唯一识别用户的,并能用于从 user_loader 回调中 加载用户的 unicode 。注意着 必须 是一个 unicode ——如果 ID 原本是 一个 int 或其它类型,你需要把它转换为 unicode 。
 
is_authenticated()
当用户通过验证时,也即提供有效证明时返回 True
 
is_active()
如果这是一个通过验证、已激活、未被停用的账户返回 True 。
 
is_anonymous()
如果是一个匿名用户,返回 True 。
 
login.py
#encoding:utf-8
#!/usr/bin/env python
from flask import render_template, request, redirect, Flask, Blueprint
from flask_login import login_user, login_required
from model.user_model import User
from model import login_manager
from form.login_form import LoginForm userRoute = Blueprint('user', __name__, url_prefix='/user', template_folder='templates', static_folder='static') @login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id)) @userRoute.before_request
def before_request():
pass @userRoute.route('/success')
@login_required
def index():
return render_template('success.html') @userRoute.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST':
if not form.validate_on_submit():
print form.errors
return render_template('login.html', form=form) user = User.query.filter(User.accountNumber == form.accountNumber.data,
User.password == form.password.data).first()
if user:
login_user(user)
return render_template('success.html') return render_template('login.html', form=form)

  

其中,要实现一个load_user()回调方法,这个回调用于从会话中存储的用户 ID 重新加载用户对象,id存在则返回对应的用户对象,不存在则返回none。
 
有些操作是需要用户登录的,有些操作则无需用户登录,这里使用到了@login_required,在每一个需要登录才能访问的路由方法上加@login_required即可。
 
启动类,runserver.py
# config=utf-8
from login import userRoute
from model import create_app DEFAULT_MODULES = [userRoute] app = create_app('../config.py') for module in DEFAULT_MODULES:
app.register_blueprint(module) @app.before_request
def before_request():
pass if __name__ == '__main__':
app.run(debug=True)

  

DEFAULT_MODULES = [userRoute]是将userRoute蓝图注册入app,才能启动login中的userRoute路由,我们在login.py中使用了蓝图:userRoute = Blueprint('user', __name__, url_prefix='/user', template_folder='templates', static_folder='static')

@app.before_request
def before_request():
pass
这是一个全局的方法,在请求开始之前被调用,在某些场景下做一些提示或者特殊处理,当然这里没用上,直接pass,这个方法去掉对项目没有影响。
 
基本样式模版,base.html
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<script src="{{ url_for('static', filename='jquery1.42.min.js') }}"></script>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>

  

登录前台页面,login.html

{% extends "base.html" %}
{% block title %}python flask user page{% endblock %}
{% block head %}
<style type="text/css"></style>
{% endblock %}
{% block content %}
<form action="{{ url_for('user.login') }}" method="post">
{% if form.errors %}
<ul>
{% for name, errors in form.errors.items() %}
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
{% endif %}
账号:{{ form.accountNumber(size=20) }}<label>{{ form.accountNumber.errors[0] }}</label><br/>
密码:<input name="password" type="password"/><br/>
{{ form.hidden_tag() }}
<button type="submit">登录</button>
</form>
{% endblock %}

  

到此,一个Flask实现简单登录功能就做完了。

python之Flask实现登录功能的更多相关文章

  1. Python Django 2.1登录功能_1

    #在上篇的基础上进行#在.../sign/templates/index.html文件,开发登录表单 <html> <head> <title>Django Pag ...

  2. Python Django 2.2登录功能_2

    #Now 让我们继续对上篇的登录进行操作 #对于csrf,以后再开篇章记录 #修改index.html <form method="post" action="/l ...

  3. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  4. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(三)——使用Flask-Login库实现登录功能

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  5. 我的第一个python web开发框架(14)——后台管理系统登录功能

    接下来正式进入网站的功能开发.要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX. 在进行接口开发之前, ...

  6. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(五)——实现注册功能

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  7. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(四)——对 run.py 的调整

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  8. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  9. Python基础入门-函数实战登录功能

    ''' 函数实战: .加法计算器 .过滤器 .登录功能实战 ''' def add(a,b): return a+b def login_order(): return 'asdfasdfdasfad ...

随机推荐

  1. (NO.00001)iOS游戏SpeedBoy Lite成形记(四)

    下面我们来实现选手从起点开始移动到终点的代码. 首先在GameScene.h接口中添加matchRun方法: #import "CCNode.h" @interface GameS ...

  2. Java关键字之static

    static 表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被stati ...

  3. 数据结构基础(3) --Permutation & 插入排序

    Permutation(排列组合) 排列问题: 设R = {r1, r2, ... , rn}是要进行排列的n个元素, Ri = R-{ri}; 集合X中元素的全排列记为Permutation(X), ...

  4. APP-FND-00676: 弹性域例程 FDFGDC 无法读取为此说明性弹性域指定的默认引用字段

    路径: AR: 设置- 财务系统 - 弹性域- 说明性 -注册 手工增加: RECEIPT_METHOD_ID 路径: AR: 设置- 财务系统 - 弹性域- 说明性 -段 路径:收款 - 收款 点  ...

  5. Cocos2D场景中对象引用为nil时的判断

    如果该对象在SpriteBuilder中属性中设置了name,则检查是否 [self.scene getChildByName:@"theNameOfTheNode" recurs ...

  6. 中国象棋游戏Chess(2) - 走棋

    之前的文章请看:中国象棋游戏Chess(1) - 棋盘绘制以及棋子的绘制 现在实现走棋的功能. 首先需要获取点击到的棋子,用QWidget中的函数 mouseReleaseEvent 实现函数: vo ...

  7. iOS 网络编程模式总结

    IOS 可以采用三类api 接口进行网络编程,根据抽象层次从低到高分别为socket方式.stream方式.url 方式. 一 .socket 方式 IOS 提供的socket 方式的网络编程接口为C ...

  8. AngularJS进阶(八)实现页面跳转并进行参数传递

    angularjs实现页面跳转并进行参数传递 注:请点击此处进行充电! Angular页面传参有多种办法,我在此列举4种最常见的: 1. 基于ui-router的页面跳转传参 (1) 在Angular ...

  9. 基于阻塞队列的生产者消费者C#并发设计

    这是从上文的<<图文并茂的生产者消费者应用实例demo>>整理总结出来的,具体就不说了,直接给出代码,注释我已经加了,原来的code请看<<.Net中的并行编程-7 ...

  10. 使用swagger管理接口

    swagger 配置 1.pom 增加jar包依赖 <dependency> <groupId>io.springfox</groupId> <artifac ...