使用flask框架实现简单的图书管理(python 3.8)

2020-12-30 15:48:02 浏览数 (1)

参考链接: 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>

0 人点赞