参考链接: Python | 在Flask中使用for循环
前言
这几天学习了flask的框架,这里总结一些学习的历程
一、flask是什么?
flask是轻量级的web框架。 浏览器作为client发出HTTP请求,而web服务器负责处理逻辑,而flask帮助我们完成了安全性和数据流的控制,让我们只用关注于业务逻辑本身,避免重复造轮子
#mermaid-svg-HRRqparv9Sv4645N .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-HRRqparv9Sv4645N .label text{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .node rect,#mermaid-svg-HRRqparv9Sv4645N .node circle,#mermaid-svg-HRRqparv9Sv4645N .node ellipse,#mermaid-svg-HRRqparv9Sv4645N .node polygon,#mermaid-svg-HRRqparv9Sv4645N .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-HRRqparv9Sv4645N .node .label{text-align:center;fill:#333}#mermaid-svg-HRRqparv9Sv4645N .node.clickable{cursor:pointer}#mermaid-svg-HRRqparv9Sv4645N .arrowheadPath{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-HRRqparv9Sv4645N .flowchart-link{stroke:#333;fill:none}#mermaid-svg-HRRqparv9Sv4645N .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-HRRqparv9Sv4645N .edgeLabel rect{opacity:0.9}#mermaid-svg-HRRqparv9Sv4645N .edgeLabel span{color:#333}#mermaid-svg-HRRqparv9Sv4645N .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-HRRqparv9Sv4645N .cluster text{fill:#333}#mermaid-svg-HRRqparv9Sv4645N div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-HRRqparv9Sv4645N .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-HRRqparv9Sv4645N text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-HRRqparv9Sv4645N .actor-line{stroke:grey}#mermaid-svg-HRRqparv9Sv4645N .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-HRRqparv9Sv4645N .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-HRRqparv9Sv4645N #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-HRRqparv9Sv4645N .sequenceNumber{fill:#fff}#mermaid-svg-HRRqparv9Sv4645N #sequencenumber{fill:#333}#mermaid-svg-HRRqparv9Sv4645N #crosshead path{fill:#333;stroke:#333}#mermaid-svg-HRRqparv9Sv4645N .messageText{fill:#333;stroke:#333}#mermaid-svg-HRRqparv9Sv4645N .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-HRRqparv9Sv4645N .labelText,#mermaid-svg-HRRqparv9Sv4645N .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-HRRqparv9Sv4645N .loopText,#mermaid-svg-HRRqparv9Sv4645N .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-HRRqparv9Sv4645N .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-HRRqparv9Sv4645N .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-HRRqparv9Sv4645N .noteText,#mermaid-svg-HRRqparv9Sv4645N .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-HRRqparv9Sv4645N .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-HRRqparv9Sv4645N .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-HRRqparv9Sv4645N .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-HRRqparv9Sv4645N .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .section{stroke:none;opacity:0.2}#mermaid-svg-HRRqparv9Sv4645N .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-HRRqparv9Sv4645N .section2{fill:#fff400}#mermaid-svg-HRRqparv9Sv4645N .section1,#mermaid-svg-HRRqparv9Sv4645N .section3{fill:#fff;opacity:0.2}#mermaid-svg-HRRqparv9Sv4645N .sectionTitle0{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .sectionTitle1{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .sectionTitle2{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .sectionTitle3{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-HRRqparv9Sv4645N .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .grid path{stroke-width:0}#mermaid-svg-HRRqparv9Sv4645N .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-HRRqparv9Sv4645N .task{stroke-width:2}#mermaid-svg-HRRqparv9Sv4645N .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .taskText:not([font-size]){font-size:11px}#mermaid-svg-HRRqparv9Sv4645N .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-HRRqparv9Sv4645N .task.clickable{cursor:pointer}#mermaid-svg-HRRqparv9Sv4645N .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-HRRqparv9Sv4645N .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-HRRqparv9Sv4645N .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-HRRqparv9Sv4645N .taskText0,#mermaid-svg-HRRqparv9Sv4645N .taskText1,#mermaid-svg-HRRqparv9Sv4645N .taskText2,#mermaid-svg-HRRqparv9Sv4645N .taskText3{fill:#fff}#mermaid-svg-HRRqparv9Sv4645N .task0,#mermaid-svg-HRRqparv9Sv4645N .task1,#mermaid-svg-HRRqparv9Sv4645N .task2,#mermaid-svg-HRRqparv9Sv4645N .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-HRRqparv9Sv4645N .taskTextOutside0,#mermaid-svg-HRRqparv9Sv4645N .taskTextOutside2{fill:#000}#mermaid-svg-HRRqparv9Sv4645N .taskTextOutside1,#mermaid-svg-HRRqparv9Sv4645N .taskTextOutside3{fill:#000}#mermaid-svg-HRRqparv9Sv4645N .active0,#mermaid-svg-HRRqparv9Sv4645N .active1,#mermaid-svg-HRRqparv9Sv4645N .active2,#mermaid-svg-HRRqparv9Sv4645N .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-HRRqparv9Sv4645N .activeText0,#mermaid-svg-HRRqparv9Sv4645N .activeText1,#mermaid-svg-HRRqparv9Sv4645N .activeText2,#mermaid-svg-HRRqparv9Sv4645N .activeText3{fill:#000 !important}#mermaid-svg-HRRqparv9Sv4645N .done0,#mermaid-svg-HRRqparv9Sv4645N .done1,#mermaid-svg-HRRqparv9Sv4645N .done2,#mermaid-svg-HRRqparv9Sv4645N .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-HRRqparv9Sv4645N .doneText0,#mermaid-svg-HRRqparv9Sv4645N .doneText1,#mermaid-svg-HRRqparv9Sv4645N .doneText2,#mermaid-svg-HRRqparv9Sv4645N .doneText3{fill:#000 !important}#mermaid-svg-HRRqparv9Sv4645N .crit0,#mermaid-svg-HRRqparv9Sv4645N .crit1,#mermaid-svg-HRRqparv9Sv4645N .crit2,#mermaid-svg-HRRqparv9Sv4645N .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-HRRqparv9Sv4645N .activeCrit0,#mermaid-svg-HRRqparv9Sv4645N .activeCrit1,#mermaid-svg-HRRqparv9Sv4645N .activeCrit2,#mermaid-svg-HRRqparv9Sv4645N .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-HRRqparv9Sv4645N .doneCrit0,#mermaid-svg-HRRqparv9Sv4645N .doneCrit1,#mermaid-svg-HRRqparv9Sv4645N .doneCrit2,#mermaid-svg-HRRqparv9Sv4645N .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-HRRqparv9Sv4645N .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-HRRqparv9Sv4645N .milestoneText{font-style:italic}#mermaid-svg-HRRqparv9Sv4645N .doneCritText0,#mermaid-svg-HRRqparv9Sv4645N .doneCritText1,#mermaid-svg-HRRqparv9Sv4645N .doneCritText2,#mermaid-svg-HRRqparv9Sv4645N .doneCritText3{fill:#000 !important}#mermaid-svg-HRRqparv9Sv4645N .activeCritText0,#mermaid-svg-HRRqparv9Sv4645N .activeCritText1,#mermaid-svg-HRRqparv9Sv4645N .activeCritText2,#mermaid-svg-HRRqparv9Sv4645N .activeCritText3{fill:#000 !important}#mermaid-svg-HRRqparv9Sv4645N .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-HRRqparv9Sv4645N g.classGroup text .title{font-weight:bolder}#mermaid-svg-HRRqparv9Sv4645N g.clickable{cursor:pointer}#mermaid-svg-HRRqparv9Sv4645N g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-HRRqparv9Sv4645N g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-HRRqparv9Sv4645N .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-HRRqparv9Sv4645N .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-HRRqparv9Sv4645N .dashed-line{stroke-dasharray:3}#mermaid-svg-HRRqparv9Sv4645N #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N .commit-id,#mermaid-svg-HRRqparv9Sv4645N .commit-msg,#mermaid-svg-HRRqparv9Sv4645N .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-HRRqparv9Sv4645N g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-HRRqparv9Sv4645N g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-HRRqparv9Sv4645N g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-HRRqparv9Sv4645N g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-HRRqparv9Sv4645N .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-HRRqparv9Sv4645N .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-HRRqparv9Sv4645N .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-HRRqparv9Sv4645N .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-HRRqparv9Sv4645N .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-HRRqparv9Sv4645N .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-HRRqparv9Sv4645N .edgeLabel text{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-HRRqparv9Sv4645N .node circle.state-start{fill:black;stroke:black}#mermaid-svg-HRRqparv9Sv4645N .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-HRRqparv9Sv4645N #statediagram-barbEnd{fill:#9370db}#mermaid-svg-HRRqparv9Sv4645N .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-HRRqparv9Sv4645N .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-HRRqparv9Sv4645N .statediagram-state .divider{stroke:#9370db}#mermaid-svg-HRRqparv9Sv4645N .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-HRRqparv9Sv4645N .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-HRRqparv9Sv4645N .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-HRRqparv9Sv4645N .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-HRRqparv9Sv4645N .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-HRRqparv9Sv4645N .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-HRRqparv9Sv4645N .note-edge{stroke-dasharray:5}#mermaid-svg-HRRqparv9Sv4645N .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-HRRqparv9Sv4645N .error-icon{fill:#522}#mermaid-svg-HRRqparv9Sv4645N .error-text{fill:#522;stroke:#522}#mermaid-svg-HRRqparv9Sv4645N .edge-thickness-normal{stroke-width:2px}#mermaid-svg-HRRqparv9Sv4645N .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-HRRqparv9Sv4645N .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-HRRqparv9Sv4645N .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-HRRqparv9Sv4645N .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-HRRqparv9Sv4645N .marker{fill:#333}#mermaid-svg-HRRqparv9Sv4645N .marker.cross{stroke:#333}
:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}
#mermaid-svg-HRRqparv9Sv4645N {
color: rgba(0, 0, 0, 0.75);
font: ;
}
请求
浏览器/client
web服务器
二、学习步骤
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>