网站少不了要和数据库打交道,归根到底都是一些增删改查操作,这里做一个简单的用户登录功能来学习一下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. 实例分析exec函数

    fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间.堆.栈等资源的副本.注意,子进程持有的是上述存储空间的"副本&quo ...

  2. 测试access函数

    测试程序: 测试结果: chown root access.out 将用户ID改为root chmod u+s access.out 打开 set-user-ID位

  3. Linux的常用命令(1) - 指定运行级别

    命令:init [0123456] 运行级别 0:关机 1:单用户 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用运行级别是3和5,要 ...

  4. Android Data Binding语法解析(二)

    上篇我们知道了Data Binding的最简单的用法,那么Data Binding其中最为重要也是最复杂的其实就是在xml布局文件中给对应的控件进行数据绑定了,接下来就一一说明Data Binding ...

  5. C++开发基础

    硬件配置: 586以上PC兼容机或品牌机,配有彩色显示器.鼠标.键盘,内存不小于20MB,硬 盘自由空间不少于60MB.推荐配置为内存32MB或64MB(或以上),硬盘自由空间500MB 以上. 软件 ...

  6. Android实训案例(二)——Android下的CMD命令之关机重启以及重启recovery

    Android实训案例(二)--Android下的CMD命令之关机重启以及重启recovery Android刚兴起的时候,着实让一些小众软件火了一把,切水果,Tom猫,吹裙子就是其中的代表,当然还有 ...

  7. Android热补丁技术—dexposed原理简析(手机淘宝采用方案)

    上篇文章<Android无线开发的几种常用技术>我们介绍了几种android移动应用开发中的常用技术,其中的热补丁正在被越来越多的开发团队所使用,它涉及到dalvik虚拟机和android ...

  8. 对于CocoaPods的简单理解,实践安装使用过程和常见问题

    (本文是自己通过其他文章进行的自我编辑和简单修改,请大家凑活看看) 一.什么是CocoaPods CocoaPods是iOS项目的依赖管理工具,该项目源码在Github上管理.开发iOS项目不可避免地 ...

  9. openresty+websocket+redis simple chat

    openresty 很早就支持websocket了,但是早期的版本cosocket是单工的,处理起来比较麻烦参见邮件列表讨论 websocket chat,后来的版本cosocket是双全工的,就可以 ...

  10. CSS基础:层叠顺序和层叠上下文

    简介 在考虑到两个元素可能重叠的情况下,层叠顺序决定了那个元素在前面,那个元素在后面,这是针对普通元素而言.而层叠上下文和块级格式化上下文 (BFC) 一样,基本上也是由一些 CSS 属性创建的,它单 ...