前言
这几天学习了flask的框架,这里总结一些学习的历程一、flask是什么?
flask是轻量级的web框架。 浏览器作为client发出HTTP请求,而web服务器负责处理逻辑,而flask帮助我们完成了安全性和数据流的控制,让我们只用关注于业务逻辑本身,避免重复造轮子
二、学习步骤
1.我的第一个flask程序
需要注意的点:
(1) 此flask程序运行在flask提供的简易服务器上,flask包括路由模块与模板引擎两个部分。所以需要提供服务器地址,@app.route(’/’)就提供了地址,默认是根目录,且默认是支持GET,再后面的WTF表单使用上我们还能用到POST(其实就是类似于输入账号密码)然后得到反馈。
(2)路由模块之后紧接着就是模板引擎,模板引擎可以返回一个字符串或者是一个html文件,html文件需要render_template模块的支持。而html文件中为了在页面中显示后端的传来的数据,需要使用变量代码块以及控制代码块,通常有两个花括号,参考下方的html代码
代码如下:
#导入flask扩展
from flask import Flask,render_template
from flask_sqlalchemy import SQLAlchemy
#创建flask应用程序实例,需要传入__name__,为了确定资源所在路径
app = Flask(__name__)
#定义路由以及视图函数,通过装饰器,根路由
#路由默认只支持GET,如果需要增加,需要自行指定
@app.route('/')
def index():
# return '<h1>Hello World!</h1>'
#传入网址,模板引擎的使用
#变量代码块的使用
url_str ='www.xidian.com'
my_list=[1,2,3,4,5]
my_dict={
'name':'czz' ,
'url':'www.xidian.com'
}
return render_template('index.html',
url_str=url_str,
my_list=my_list,
my_dict=my_dict)
# <>定义路由参数,<>内需要起个名字
@app.route('/orders/<int:order_id>')
def get_order_id(order_id):
#需要在视图函数内填入参数名,后面代码才能使用
print(type(order_id))
return 'order_id %s'%order_id
if __name__ == '__main__':
#将Flask程序运行在一个简易服务器上(flask提供)
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是模板<br>
这是首页<br>
<!--下面是一个变量代码块的使用-->
{{my_list}}<br>
{{my_list[2]}}<br>
{{my_dict}}<br>
{{my_dict.name}}<br>
{{url_str}}<br>
<hr>
<!--控制代码块,用花括号,基本语法仍然相同-->
{% for num in my_list %}
{% if num>3 %}
{{num}}<br>
{% endif %}
{% endfor %}
<hr>
<!--过滤器-->
{{ url_str | upper}}<br>
{{ url_str | reverse}}<br>
<!--过滤器链式调用-->
{{ url_str | reverse | upper}}<br>
</body>
</html>
结果显示:
2.实现简单的登录逻辑
问题分析:
(1). WTF为我们封装了登录的相关的逻辑,我们利用wtf来实现表单类,继承自FlaskForm
(2) .我们需要有登录账号,密码,以及密码确认。因此需要username,以及password1,password2,submit。validators是为了表单的验证,如果有表单数据有误会在页面中显示参数错误。
(3).我们为了需要完成与前端的页面的交互,必须利用模板引擎来定义表单类并获取请求的参数
(4)注意利用wtf实现表单类的时候需要设置secret_key进行加密,并在前端代码中加入{{ form.csrf_token() }}
代码如下:
from flask import Flask,render_template,request,flash
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,EqualTo
app=Flask(__name__)
app.secret_key='xdu'
#目的:实现简单的登录逻辑处理
#路由需要有get和post两种请求方式,需要判断请求方式
#获取请求参数
#判断参数是否填写以及密码是否相同
#如果判断没有问题则返回一个success
'''
给模板传递消息
flash 需要对内容加密,需要设置secret_key,做加密消息的混淆
模板中需要遍历消息
'''
'''
使用wtf实现表单类
'''
class LoginForm(FlaskForm):
username=StringField('用户名',validators=[DataRequired()])
password=PasswordField('密码',validators=[DataRequired(),EqualTo('password','密码不一致')])
password2 = PasswordField('确认密码')
submit=SubmitField('提交')
@app.route('/form',methods=['GET','POST'])
def login():
login_form=LoginForm()
# 1.request 是一个请求对象-->获取请求方式,数据.
if request.method == 'POST':
# 2.获取请求参数
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
# 3.wtf验证逻辑的实现
if login_form.validate_on_submit():
print(username , password)
return 'success'
else:
flash('参数有误')
return render_template('index.html',form=login_form)
@app.route('/',methods=['GET','POST'])
def index():
#1.request 是一个请求对象-->获取请求方式,数据.
if request.method =='POST':
#2.获取请求参数
username =request.form.get('username')
password =request.form.get('password')
password2 = request.form.get('password2')
# 3.判断参数是否相同 密码是否相同
if not all([username,password,password2]):
# print('参数不完整')
flash('参数不完整')
elif password!=password2:
# print('密码不一致')
flash('密码不一致')
else: return 'success'
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
<label>用户名:</label><input type="text" name="username"><br>
<label>密码:</label><input type="password" name="password"><br>
<label>确认密码:</label><input type="password" name="password2"><br>
<input type="submit" value="提交"><br>
{% for message in get_flashed_messages() %}
{{message}}
{% endfor %}
</form>
<hr>
<form method="post">
{{ form.csrf_token() }}
{{form.username.label}}{{form.username}}<br>
{{form.password.label}}{{form.password}}<br>
{{form.password2.label}}{{form.password2}}<br>
{{form.submit}}
</form>
</body>
</html>
3.数据库相关配置
这里进行配置数据库,并建立两张表,一张是角色,一张是用户。
User希望有role属性,这个属性的定义需要在另一个模型中定义 使得user可以直接查到role,这样做的目的是为了方便查找,两个模型之间实现了关联
# coding=<encoding name> : # coding=utf-8
from flask import Flask, render_template, redirect, url_for, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CSRFProtect
import pymysql
app = Flask(__name__)
#设置数据库配置信息
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1:3306/flask_use_sql'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #压制警告信息
db=SQLAlchemy(app)
app.config['SECRET_KEY'] = "jfkdjfkdkjf"
'''
需求:两张表
角色(管理员/普通用户)
用户(角色ID)
'''
#数据库模型,需要继承db.Modelf
class Role(db.Model):
#定义表名
__tablename__='roles'
#定义字段 db.Column表示是一个字段
id=db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64), unique=True)
#在一的一方,写关联
#表示和User模型发生关联,增加了一个users属性
user=db.relationship('User', backref='role')
# 重写__repr__方法,方便查看对象输出内容
def __repr__(self):
return 'Role:%s'% self.name
class User(db.Model):
__tablename__='users'
id=db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(16), unique=True)
email = db.Column(db.String(64), unique=True)
password = db.Column(db.String(64))
# db.ForeignKey('roles.id') 表示是外键,需要用 表名.id形式表示
role_id=db.Column(db.Integer,db.ForeignKey('roles.id'))
#User希望有role属性,这个属性的定义需要在另一个模型中定义 使得user可以直接查到role 反之亦然
def __repr__(self):
return '<User:%s %s %s %s >' % self.name,self.id,self.email,self.password
@app.route('/')
def index():
return 'hello flask'
if __name__ == '__main__':
# #删除表
db.drop_all()
# #创建表
db.create_all()
role=Role(name='admin')
db.session.add(role)
db.session.commit()
user1= User(name='czz',role_id=role.id)
user2 = User(name='lisi', role_id=role.id)
db.session.add_all([user1,user2])
db.session.commit()
# user.name='czz tcl'
db.session.commit()
# db.session.delete(user)
# db.session.commit()
# print(user2.role)
app.run(debug=True)
图书管理的实现
# -*- coding:utf-8 -*-
from flask import Flask, render_template, redirect, url_for, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms.validators import DataRequired
from wtforms import StringField,SubmitField
from flask_wtf.csrf import CSRFProtect
#import sys
#reload(sys)
#sys.setdefaultencoding("utf-8")
app=Flask(__name__)
#配置数据库 数据库地址 关闭自动跟踪修改
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1:3306/flask_project_demo'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #压制警告信息
app.config['SECRET_KEY'] = "123456"
# #开启csrf保护
# CSRFProtect(app)
#创建数据库对象
db=SQLAlchemy(app)
'''
1.配置数据库
a.导入SQLAlchemy扩展
b.创建db对象,并配置参数
c.创建终端数据库
2.添加书和作者的模型
a.模型继承db.Model
b.__tablename__表名
c.db.Column:字段
d.db.relationship:关系引用
3.添加数据
4.使用模板显示数据库查询的数据
a.查询所有作者信息,让信息传给模板
b.模板中按照格式,依次for循环作者和书籍即可
5.使用wtf显示表单
a.自定义表单类
b.模板中显示
c.secret_key/编码/csrf_token
6.实现相关的增删逻辑处理
a.增加数据
b.删除书籍 -->网页中删除--点击需要发送书籍的ID给删除书籍的路由-->路由需要接收参数
url_for的使用 /for else 的使用/ redirect的使用
c.删除
'''
#定义书和作者模型
#作者模型
class Author(db.Model):
# 表名
__tablename__ = 'authors'
# 字段
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64), unique=True)
# 关系引用
# books自己使用,author是给book模型使用的
books = db.relationship('Book',backref='author')
def __repr__(self):
return 'Author:%s' % self.name
class Book(db.Model):
__tablename__='books'
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64), unique=True)
author_id=db.Column(db.Integer,db.ForeignKey('authors.id'))
def __repr__(self):
return 'Book:%s' % (self.name,self.author_id)
#自定义表单类:
class AuthorForm(FlaskForm):
author =StringField('作者', validators=[DataRequired()])
book = StringField('书籍', validators=[DataRequired()])
submit=SubmitField('提交')
#删除作者
@app.route('/delete_author/<author_id>')
def delete_author(author_id):
# 查询数据库,是否有改ID的作者,如果有就删除(先删除书后删除作者)
# 1.查询数据库
author =Author.query.get(author_id)
# 2.如果有就删除
if author:
try:
# 查询后直接删除
Book.query.filter_by(author_id=author_id).delete
# 删除作者
db.session.delete(author)
db.session.commit()
except Exception as e:
print(e)
flash('删除作者错误')
db.session.rollback()
else:
# 没有提示错误
flash('作者找不到')
return redirect(url_for('index'))
# 删除书籍 -->网页中删除--> 点击需要发送书籍的ID给删除书籍的路由-->路由需要接收参数
@app.route('/delete_book/<book_id>')
def delete_book(book_id):
# 1.查询数据库是否有该id的书,如果有就删除,没有就提示错误
book=Book.query.get(book_id)
# 2.如果有就删除
if book:
try:
db.session.delete(book)
db.session.commit()
except Exception as e:
print(e)
flash('删除书籍错误')
db.session.rollback()
else:
# 3.没有提示错误
flash('书籍找不到')
# 如何返回当前网址——>重定向
# redirect:重定向,需要传入网址/路由地址
# url_for:需要传入视图函数名,返回该视图函数对应的路由地址
return redirect(url_for('index'))# 结果和redirect('/')一样
@app.route('/',methods=['GET','POST'])
def index():
#创建自定义的表单类
author_form=AuthorForm()
'''
验证逻辑:
1.调用wtf的函数实现验证
2.验证通过获取数据
3.判断作者是否存在
4.如果作者存在,判断书籍是否存在,如果没重复就添加数据,反之提示错误
5。作者不存在,添加作者和书籍
6.验证不通过就提示错误
'''
#1.调用WTF的函数实现验证
if author_form.validate_on_submit():
#2.通过验证获取数据
author_name=author_form.author.data
book_name = author_form.book.data
#3.判断作者是否存在
author=Author.query.filter_by(name=author_name).first()
#4.如果作者存在
if (author) :
# 判断书籍是否存在
book=Book.query.filter_by(name=book_name).first()
if (book):
flash('存在同名书籍')
#没有重复的书籍就添加数据
else:
try:
new_book=Book(name=book_name,author_id=author.id)
db.session.add(new_book)
db.session.commit()
except Exception as e:
print(e)
flash('添加书籍失败')
db.session.rollback()
pass
else:
#5.作者不存在,添加作者和书籍
try:
new_author = Author(name=author_name)
db.session.add(new_author)
db.session.commit()
new_book = Book(name=book_name, author_id=new_author.id)
db.session.add(new_book)
db.session.commit()
except Exception as e:
print(e)
flash('添加作者和书籍失败')
db.session.rollback()
pass
pass
else:
if request.method == 'POST':
flash('参数不全')
# 查询所有的作者信息,让信息查给模板
authors = Author.query.all()
return render_template('library.html', authors=authors, form=author_form)
if __name__ =='__main__':
# 为了演示方便,先删除所有表,再创建
db.drop_all()
db.create_all()
# 添加测试数据库
# 生成数据
au1 = Author(name='隔壁老王')
au2 = Author(name='老李')
au3 = Author(name='二营长')
# 把数据提交给用户会话
db.session.add_all([au1, au2, au3])
# 提交会话
db.session.commit()
bk1 = Book(name='learn', author_id=au1.id)
bk2 = Book(name='science', author_id=au1.id)
bk3 = Book(name='art', author_id=au2.id)
bk4 = Book(name='beautiful', author_id=au3.id)
bk5 = Book(name='handsome', author_id=au3.id)
# 把数据提交给用户会话
db.session.add_all([bk1, bk2, bk3, bk4, bk5])
# 提交会话
db.session.commit()
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{{ form.csrf_token()}}
{{ form.author.label()}}{{form.author}}
{{ form.book.label()}}{{form.book}}
{{ form.submit }}
<!-- 显示消息闪现的内容-->
{% for message in get_flashed_messages() %}
{{message}}
{% endfor %}
</form>
<hr>
<ul>
<!-- #先遍历作者,然后在作者里遍历书籍-->
{% for author in authors %}
<li>{{ author.name }}<a href="{{url_for('delete_author',author_id=author.id)}}">删除</a> </li></li>
<ul>
{% for book in author.books %}
<li>{{ book.name }}<a href="{{url_for('delete_book',book_id=book.id)}}">删除</a> </li>
{% else %}
<li>无</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
</body>
</html>