【flask】使用Flask快速上手web开发

【flask】使用Flask快速上手web开发,第1张

使用Flask快速上手web开发 Flask简简简介
  • 是干嘛的?

    一个web框架,基于Python,可以快速搭建web后端

  • 优点

    • 基于Python,开发效率很高
    • 默认提供Jinija2模板引擎,如果仅仅是开发小型web,那么flask可以把前端也一起包了
    • 可以很方便地 *** 作数据库
  • 本文要讲什么

    • 简单介绍一下flask框架,并且通过三个小示例说明如何使用flask开发简单的前后端不分离web应用。小示例如下:
      1. 开发用户注册和登录模块,不同的用户对数据库有不同的 *** 作权限(浏览数据库和编辑数据库)。(提示:在注册时将有关信息保存到数据库中;当再次登录时,根据用户输入的用户名和密码在数据库中查找,不同的用户给出不同的页面进行 *** 作。)
      2. 开发一个简单的在线考试程序,可以包括若干道单选题、多选题,单击交卷 按钮后就可以根据标准答案在线评分。
      3. 开发一个页面,当客户第一次访问时,需在线注册姓名、性别等信息,然后将信息保存到 Cookies 中,当下次如该用户再访问,则显示“某某,您好,您是第几次光临本站”的欢迎信息。
如何安装软件包
  • 由于我安装了一个丰富的anaconda,故许多包都不需要再手动安装。如果有需要的话,pycharm中安装软件包的方法如下:
先运行起来再说
  • flask的开发推荐使用pycharm进行。如果没有的话,vscode也可以。本文使用pycharm进行开发。

  • 新建项目,选择flask,选择环境(注:后续所有pip install全部是装在此环境中。如果是练习,建议共用一个环境;如果要开发一个项目,建议选择一个新环境),点击create。这样就创建了一个新项目。

  • 创建成功后可以看到目录结构如下图所示。简单介绍一下,static用于存放静态资源(如css文件、js文件等等),templates用于存放Jinijia模板(html文件),现在都是空的

    .py为结尾的全部是后端的文件。

    点击运行,浏览器打开http://127.0.0.1:5000/(5000是默认端口,可以修改的),可以看到Hello World。好耶!

    • 解释一下这里的逻辑:

      app.route是一个映射器,将url和函数进行一一映射

      代码中,app.route将/映射为hello_world函数,故访问http://127.0.0.1:5000/,实际上相当于执行了hello_world函数

      hello_world返回了一个字符串,Jinija将这个字符串渲染为一个网页,于是在页面上呈现了字符串的内容

  • debug选项的配置

    默认情况下pycharm不打开debug配置,这种情况下改动代码必须重新运行项目才能将改动反映到localhost上

    开发过程中可以在下面打开debug选项,flask会在每次保存代码的时候自动的重新载入代码,并且如果代码有错误,会在终端进行提示,便于随时调试代码

初识url与视图函数
  • 上面的例子中,我们可以在页面上看到Hello World。为什么呢?要回答这个问题首先来看两个东西:

  • @app.route

    @app.route是装饰器,用于将url映射到一个函数(也就是紧随其后的那个函数)。当浏览器访问这个url时,flask后端就调用这个函数

  • 视图函数

    这种被@app.route进行映射的函数就是视图函数。之所以叫这个名字,因为浏览器端的页面展示完全取决于这个函数的返回值

来点前端吧
  • 开发小型web页面显然不能仅仅返回字符串,而要返回一个像样一点的html页面。那么我们就不能只靠视图函数的return来实现了

    我们可以在template文件夹中写一些html代码,并且在static目录下写一些配套的css、js代码,最后在视图函数中返回这个页面即可

  • 下面简单的写了一个html文件,放在template中,随便配了点样式:

        <form action="/login-check" method="post" class="container">
            <div class="form">
                <span>用户名:span>
                <input type="text" name="username" placeholder="请输入用户名">
            div>
            <div class="form">
                <span>密 码:span>
                <input type="password" name="password" placeholder="请输入密码">
            div>
            <button type="submit">登录button>
        form>
    

    那么,要如何让用户访问http://127.0.0.1:5000/login/时看到这个html文件呢?可以在视图函数的return返回render_template渲染的Jinija模板,如下:

    然后访问login,发现展示了这个页面

后端拿到表单数据
  • 用户输入表单数据后,后端如何拿到呢?
  1. 首先,前端form表格的action位置填入一个url参数。本示例中填入action=“/login-check”,表示表单提交到这个url

  2. 后端使用@app.route装饰器配置一个对应的url以及对应的函数。从flask中import request,即可在函数中使用request获取前端发过来的请求,包括表单信息。如下:

    注意:

    • request必须从flask中import才能使用
    • @app.route装饰器需要配置post方法,才能响应post请求。否则,默认只能响应get请求
    • request中可以拿到所有请求信息,request.form可以拿到字典格式的表单数据,字典中的key为input框的name属性(因此,前端form中的输入框必须配置name属性)
如何 *** 作数据库
  • 拿到表单数据以后,我们就需要进行一些数据库 *** 作:登录时,需要在数据库查找用户是否存在、密码是否正确;注册时,需要将用户信息插入数据库中

  • 那么,flask如何 *** 作数据库呢?

    flask中可以使用SQLAlchemy库 *** 作sql。SQLAlchemy是一个数据库的ORM框架,让我们 *** 作数据库的时候不要再用SQL语句了,跟直接 *** 作模型一样

    本文中不使用SQLAlchemy库,而使用Flask-SQLAlchemy库进行 *** 作。Flask-SQLAlchemy是对SQLAlchemy进行了一个简单的封装,使得我们在flask中使用sqlalchemy更加的简单。可以通过pip install flask-sqlalchemy

    本文使用本地的mysql数据库

  • 安装包

    数据库 *** 作需要用到一些包,需要手动进行安装。主要有flask_sqlalchemy和pymysql包

    安装完成后,在app.py中引入

    from flask_sqlalchemy import SQLAlchemy
    
  • 连接数据库

    使用数据库的第一步是需要连接到数据库。如下:

    首先配置用户名、密码、数据库名,然后把这些全部塞到mysql的url中。最后,设置SQLALCHEMY_DATABASE_URI配置项的值为url,即可进行连接。db = SQLAlchemy(app)后,db就可以拿到这个数据库

    user = '用户名'
    password = '密码'
    database = '数据库名称'
    DB_URI = 'mysql+pymysql://%s:%[email protected]:3306/%s' % (user, password, database)
    app.config['SQLALCHEMY_DATABASE_URI'] = DB_URI
    db = SQLAlchemy(app)
    
  • 创建表

    flask中,需要通过类来 *** 作数据表的,一个类代表着一张表。类的定义可以参考下面的格式:

    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True,autoincrement=True)
        username = db.Column(db.String(50), nullable=False)
        password = db.Column(db.String(50), nullable=False)
        root = db.Column(db.Integer, default=0)
        
    db.create_all()		# 创建所有表
    

    首先,类要继承db.Model(最关键!)。然后,即可开始定义每个列的内容。db.Column中可以传入的各种约束还有很多,可以上网搜索一下

    定义完所有表以后,可以使用db.create_all()创建所有表(也就是所有继承db.Model)。当然了,也可以在数据库中建好表。但是不管建不建表,都要写类,否则无法进行插入 *** 作

  • 插入新数据

    数据库 *** 作增删改都是通过db.session.xxx完成的。做完 *** 作以后,使用db.session.commit提交 *** 作(有点类似于git)

    例如,随意在User表中插入一条数据,如下:

    # db.create_all()
    admin = User(username="root", password="123456", root=1)
    db.session.add(admin)
    db.session.commit()
    

  • 查询数据

    查询 *** 作是使用Model.query,如下:

  • 其余数据库 *** 作不再演示,查查资料吧 ~

任务1:登录注册的实现
  • 前端、后端、数据库都提到了,下面开始写第一个任务。由于仅仅是演示一下flask的使用,故旨在做通,至于前端美不美观、表单的各项验证什么的都不考虑啦

  • 任务1:开发用户注册和登录模块,不同的用户对数据库有不同的 *** 作权限(浏览数据库和编辑数据库)。(提示:在注册时将有关信息保存到数据库中;当再次登录时,根据用户输入的用户名和密码在数据库中查找,不同的用户给出不同的页面进行 *** 作。)

  • 思路:

    1. 编写一个登录页面,可以输入用户名、密码进行登录,并且配一个“去注册”按钮
    2. 编写一个注册页面,可以输入用户名、密码、是否为管理员进行注册,注册完成后自动跳转登录页面
    3. 登录后,进入首页,如果是用户,则显示欢迎信息;如果是管理员,则展示所有用户的列表

    开始吧!

  • 登录逻辑处理

    简单来说就是用用户名去查数据库,如果查不到则登录失败,如果查到了再检查密码

    登录失败后,在页面上报错;登录成功后,转到index页面,并且根据用户权限不同而显示不一样的内容

    后端代码编写如下:

    • 注意,代码中的render_template、redirect、url_for在使用前都需要从Flask包中引入
    userinfo = {}		# userinfo记录在全局变量中
    @app.route('/login/', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            return render_template('login.html', **{'msg': '您好,请登录'})
        elif request.method == 'POST':
            user = User.query.filter_by(
                username=request.form['username'],
                password=request.form['password']
            ).first()
            if user == None:
                return render_template('login.html', **{'msg': '登录失败,请检查用户名和密码'})
            userinfo['username'] = user.username
            userinfo['root'] = user.root
            userinfo['user_list'] = []
            return redirect(url_for('index'))
    
    @app.route('/index/')
    def index():
        if userinfo['root'] == 1:
            user_list = User.query.all()
            for i in user_list:
                userinfo['user_list'].append(i.username)
        return render_template('index.html', **userinfo)
    

    简单讲一下编写逻辑:

    首先,设置login可以接受get和post请求。函数中,使用request.method获取请求类型(注意必须大写),然后分别进行处理

    • get请求用于处理浏览器访问,直接返回页面即可
    • post请求用于处理表单提交,需要对表单进行验证,获取数据,返回错误提示/转到首页

    在render_template函数中可以看到我们传递了第二个参数:**字典。这表示向html页面传递一些参数,**表示将字典展开。具体含义见下一小点:登录前端页面编写

    在post处理逻辑中,首先使用输入的用户密码去查找数据库。这里选择query.filter_by方法

    如果查不到,说明登录时输入的用户/密码错误,则返回msg提示登录失败

    如果查到了,修改userinfo的值,路由至index页面。进入index后视是否为管理员决定是否从数据库中取出所有用户数据

  • 注册逻辑编写

    @app.route('/register/', methods=['GET','POST'])
    def register():
        if request.method == 'GET':
            return render_template('register.html', **{'msg': '您好,请注册'})
        elif request.method == 'POST':
            print(request.form)
            if len(request.form['username']) == 0 or len(request.form['password']) == 0:
                return render_template('login.html', **{'msg': '请完整填写信息!'})
            user = User.query.filter_by(
                username=request.form['username']
            ).first()
            if user != None:
                return render_template('login.html', **{'msg': '注册失败,用户名已存在'})
            # 插入数据库
            user = User(username=request.form['username'], password=request.form['password'], root=1 if 'root' in request.form else 0)
            db.session.add(user)
            db.session.commit()
        return redirect(url_for('login'))
    
    

    注册逻辑和登录逻辑差不多。简单讲一下:

    1. 如果是get请求,返回注册页面
    2. 如果是post请求,表示用户提交表单进行注册。首先检验表单是否为空,然后查询数据库看看用户名是否重复,最后再检查无误后插入数据库,并且重定向至,login界面
  • 登录界面编写

    前端界面的编写最需要讲一讲的是如何拿到后端传过来的数据。login.html编写如下:

        <form action="{{ url_for('login') }}" method="post" class="container">
            <div class="form">
                <span>用户名:span>
                <input type="text" name="username" placeholder="请输入用户名">
            div>
            <div class="form">
                <span>密 码:span>
                <input type="password" name="password" placeholder="请输入密码">
            div>
            <button type="submit">登录button>
        form>
        <a href="{{ url_for('register') }}"><button>去注册button>a>
        <span style="color: red;">{{ msg }}span>
    

    Jinija语法中,可以使用{{Python函数或者变量}}来获取后端传来的东西

    form action="{{ url_for(‘login’) }}"表示表单提交到login函数对应的那个url上。在flask中,这是一种比较好的习惯,因为url可能会在以后被更改,但是视图函数的名称一般不会轻易更改。因此,需要用url的地方可以全部使用url_for(视图函数名)进行代替

    {{ msg }}表示取后台传回的信息并且放到span标签中

    效果如下。进入页面后,提示请登录。如果登录信息错误,会进行提示;如果登录正确,则直接进入index页面

  • index页面编写

    这个页面故意用了很多Jinija模板语法

    • {% if xxx %}、{% for xx in xx %}都是控制语句的写法(实际上相当于插入了一些py代码)。更详细的用法可以去官网搜索
    • user_list是login函数返回的render_template中携带的数据
    • {{ user_list | length }}是过滤器语法,表示获取user_list (这是一个数组)的长度。{{}}中不能直接调用py中的len函数

    最终效果见上一条

    <body>
    {% if root == 1 %}
        <div>
            <h1>欢迎系统管理员h1>
            <span>用户列表如下:span>
            <ul>
                {% for name in user_list %}
                    <li>{{ name }}li>
                {% endfor %}
            ul>
            <span>总用户:{{ user_list | length }}人span>
        div>
    {% else %}
        <h1>欢迎用户 {{ username }}h1>
    {% endif %}
    body>
    
任务2:在线考试系统实现
  • 随便写点啦。直接上代码:

  • 数据库表类:

    class Exam(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        title = db.Column(db.String(200), nullable=False)
        a = db.Column(db.String(100), nullable=False)
        b = db.Column(db.String(100), nullable=False)
        c = db.Column(db.String(100), nullable=False)
        ans = db.Column(db.String(2), nullable=False)
    

    很简单的写了点东西,title是题目内容,a、b、c分别是三个选项,ans是答案

    当然了,真正的考试系统肯定不能这么存东西。这里能用就行啦

  • 后端:

    @app.route('/exam/', methods=['GET', 'POST'])
    def exam():
        data = Exam.query.all()
        exam_list = []
        for i in data:
            exam_list.append({
                'id': i.id,
                'title': i.title,
                'a': i.a,
                'b': i.b,
                'c': i.c,
            })
        if request.method == 'GET':
            return render_template('exam.html', **{'exam_list': exam_list})
        elif request.method == 'POST':
            score = 0
            print(request.form.to_dict())
            for key, value in request.form.to_dict().items():
                item = data[int(key) - 1]
                if int(key) == item.id and value == item.ans:
                    score += 1
            return render_template('exam.html', **{
                'exam_list': exam_list,
                'msg': '提交成功',
                'score': score,
            })
    

    主要思路还是分get和post请求进行处理

    首先,去数据库取出所有题目

    如果是get请求,直接把数据和页面返回

    如果是post请求,说明用户提交了题目答案。那么,对答案进行解析,看看有多少题正确,并且返回相应显示内容

  • 前端:

    主要是拿到后端传来的数据并且进行展示

    <div>
        <h1>欢迎考试h1>
        <form action="{{ url_for('exam') }}" method="post" class="container">
            {% for exam in exam_list %}
                <div>{{ loop.index }}. {{ exam["title"] }}<span style="color: red;">{{ right }}span>div>
                <label style="display: block;"><input type="radio" value="a" name="{{ exam['id'] }}">a. {{ exam["a"] }}
                label>
                <label style="display: block;"><input type="radio" value="b" name="{{ exam['id'] }}">b. {{ exam["b"] }}
                label>
                <label style="display: block;"><input type="radio" value="c" name="{{ exam['id'] }}">c. {{ exam["c"] }}
                label>
            {% endfor %}
            <button type="submit" style="display: block;">提交button>
        form>
        <span>提示:<span style="color: red;">{{ msg }}span>span>
        <div>总分数:<span style="color: red;">{{ score }}span>div>
    div>
    
  • 最终效果:
    写完答案再提交后,可以看到提示和总分数(提交后页面会刷新)

  • 注:flask向前端发送信息,可以使用消息闪现机制。这里不再展开

任务3:cookie使用
  • 这里偷个小懒,做成这样:用户第一次访问,提示请输入姓名;此后,每次访问都d出“某某,您好,您是第几次光临本站”

  • 读取cookie:浏览器在每次访问url时,请求中会自动带上cookie。故后端只需要使用request.cookies.get(“cookie项的名字”)即可拿到cookie

  • 写cookie:后端可以构造一个响应体,在响应体中使用set_cookie函数进行cookie信息设置

  • 后端代码:

    @app.route('/', methods=['GET', 'POST'])
    def welcome():  # put application's code here
        if request.method == 'GET':
            name = request.cookies.get("name")
            # 判断cookie是否已经存在
            if name == None:
                return render_template('welcome.html', **{
                    'msg': '您好,您是首次光临本站,请填写用户名',
                    'name': '',
                })
            else:
                time = request.cookies.get("time")
                time = str(int(time) + 1)
                resp = make_response(render_template('welcome.html', **{
                    'msg': name + ',您好,您是第' + time + '次光临本站',
                    'name': name,
                }))
                resp.set_cookie("time", time, max_age=3600)
                return resp
        elif request.method == 'POST':
            name = request.form['name']
            time = '1'
            resp = make_response(render_template('welcome.html', **{
                    'msg': name + ',您好,您是第' + time + '次光临本站',
                    'name': name,
                }))
            resp.set_cookie("name", name, max_age=3600)
            resp.set_cookie("time", time, max_age=3600)
            return resp
        return '出错啦'
    

    简单进行一下逻辑解释。进来后,如果是get请求,则查看cookie中是否有name信息。如果没有,说明是首次登录,则返回“您好,您是首次光临本站,请填写用户名”的信息。否则,time+1,设置响应体,返回响应体

    如果是post请求,说明用户填写了input表格。那么我们把这个name写入cookie中,并且写入time为1表示第一次登录,最后返回响应体

  • 前端页面:

    <body>
    <div>{{ msg }}div>
    <br/>
    {% if name == '' %}
        <form action="{{ url_for('welcome') }}" method="post" class="container">
            <input type="text" name="name" placeholder="请输入用户名">
            <button type="submit">提交button>
        form>
    {% endif %}
    body>
    

    简单写了一下。大概就是,展示msg,并且在name为空时展示input框(用于发送post请求)

  • 最终效果:

    首次访问:

    输入用户名,提交后,跳转至欢迎界面:

    进行疯狂刷新:

    可以看到cookie信息确实存入了浏览器

补充:代码重构——什么是蓝图
  • 这一章仅仅简单提一句蓝图,讲的也不是很详细。可以跳过!

  • 拿到表单数据后的下一步应该是 *** 作数据库,但是这里简单插入对蓝图的讲解

    可以看到,现在的app.py中有三个函数,分别是根路径视图函数、login路径视图函数和登录表单处理函数。现在已经略显凌乱了,可以想象,后续开发了很多页面以后,有各种各样的视图函数和功能函数,全部放在app.py中显然是不合理的,也不方便维护

    解决方法是:引入蓝图,将不同的函数放入不同的文件,最后再在app.py中注册,实现项目的模块化

  • 首先,我们需要在项目的根路径下建立一个py包(名称不限)。建好后,默认出现一个__init__.py文件

  • 然后,我们在这个blueprint包中新建一个login.py。后续所有和登录有关的逻辑全部写入这个文件中

    • 首先,定义一个bp,表示本蓝图。其中,url_prefix参数指的是该蓝图的url的前缀。下图中,定义url_prefix为’/login’,那么访问http://127.0.0.1:5000/login/时会调用login视图函数(为什么?因为前缀是/login,login函数绑定的url是/)
    • 然后,在__init__.py中导入login中的bp,方便在外面访问

  • 最后,在app.py中注册该蓝图即可。注册时使用register_bluprint函数,如下图

  • 这里就是简单提一句蓝图。实际上官网项目的目录结构不止这些

    因为后面还要引入数据库等等,要考虑很多东西,故下面就一股脑全写在app.py中了。大家要知道,这样做小东西可以,绝对不要这样开发大项目。开发大项目还是要注意目录规范喔!^_^

总结
  • 本文主要是简单介绍了一下flask的原理和使用。许多案例并不细致,甚至有很多地方并不符合工程开发规范。仅仅当作是一个简单的入门文章啦!如果有想交流的东西欢迎在评论区讨论!感谢感谢!^_^

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/714042.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-24
下一篇 2022-04-24

发表评论

登录后才能评论

评论列表(0条)

保存