zoukankan      html  css  js  c++  java
  • flask简单了解

    Flask简介:

      Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务,在介绍Flask之前首先来聊下它和Django的联系以及区别,django个大而全的web框架,它内置许多模块,flask是一个小而精的轻量级框架,Django功能大而全,Flask只包含基本的配置 Django的一站式解决的思路,能让开发者不用在开发之前就在选择应用的基础设施上花费大量时间。Django有模板,表单,路由,认证,基本的数据库管理等等内建功能。与之相反,Flask只是一个内核,默认依赖于两个外部库: Jinja2 模板引擎和 Werkzeug WSGI 工具集,其他很多功能都是以扩展的形式进行嵌入使用,相比于其他Web框架例如Django,更加灵活也更加简洁,如下几行代码就可以写出一个小程序:

    复制代码
    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'Hello Flask!'
    
    if __name__ == '__main__':
        app.run()
    复制代码

    接下来我们按照执行顺序来了解下Flask

    配置文件

    app.config.from_object("settings.DevelopmentConfig") 


    路由

      路由通过使用Flask的app.route装饰器来设置

    动态路由(url传参)

    复制代码
    @app.route('/user/<username>')
    def show_user_profile(username):
        # show the user profile for that user
        return 'User %s' % username
    
    @app.route('/post/<int:post_id>')
    def show_post(post_id):
        # show the post with the given id, the id is an integer
        return 'Post %d' % post_id
    复制代码

    如果希望获取/article/1这样的路径参数,就需要使用路径变量。路径变量的语法是/path/<converter:varname>。在路径变量前还可以使用可选的转换器,有以下几种转换器。

    转换器作用
    string 默认选项,接受除了斜杠之外的字符串
    int 接受整数
    float 接受浮点数
    path 和string类似,不过可以接受带斜杠的字符串
    any 匹配任何一种转换器
    uuid 接受UUID字符串

    HTTP方法

    如果需要处理具体的HTTP方法,在Flask中也很容易,使用route装饰器的methods参数设置即可。

    • GET 将未经加密的信息发送的服务器. 是最通用的方法.
    • HEAD 该方法除了服务端不返回响应内容只返回头信息之外, 同GET是一样的.
    • POST 用于向服务器发送HTML表单数据. POST请求不会被缓存.
    • PUT 将URL所指示的资源用上传的内容替换.
    • DELETE 将URL所指示的资源删除.
    复制代码
    from flask import request,render_template
    
    @app.route('/login', methods=['GET', 'POST'])    #如果不加methods,Flask路由默认处理的是GET请求
    def login():
        if request.method == 'POST':
            do_the_login()
        else:
            return render_template('xxx.html')
    复制代码

    url_for 和 endpoint

    复制代码
    from flask import Flask,url_for
    app=Flask(__name__)
    @app.route('/<path:url>',endpoint='XXX')        #endpoint默认为函数名
    def demo(url):
        print(url_for('XXX',url=url)) #如果设置了url参数,url_for(别名,加参数)
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()
    复制代码

    处理请求

    Request 对象

    Request 对象是一个全局对象,利用它的属性和方法,我们可以方便的获取从页面传递过来的参数。

    request.method 获取请求方法
    request.form 获取POST类型的表单提交的数据和ajax请求的数据
    request.args 获取get请求参数 
    request.values 获取GET和POST请求携带的所有参数(GET/POST通用)
    request.cookies 获取cookies信息
    request.headers 获取请求头信息
    request.path 获取cookies信息
    request.full_path 获取获取用户访问的完整url地址+参数 例如(/index/?page=1)
    request.url 获取完整路径
    request.base_url 获取访问url地址(不获取参数),例如 http://127.0.0.1:5000/;
    request.files 获取用户上传的文件

     

    响应处理

    • 返回字符串   ----return “asdf”    
    • 返回模板       ----return render_template('xxx.html')   
    • 返回重定向   ----return redirect(' /')
    • 返回字典       ----jsonify({'k1':'v1'})

      默认的错误页面是一个空页面,如果需要自定义错误页面,可以使用errorhandler装饰器。

    from flask import render_template
    
    @app.errorhandler(404)
    def page_not_found(error):
        return render_template('page_not_found.html'), 404

      我们也可以自己决定如何设置响应对象,方法也很简单,使用make_response函数即可。

    @app.errorhandler(404)
    def not_found(error):
        resp = make_response(render_template('error.html'), 404)
        resp.headers['X-Something'] = 'A value'
        return resp

    session

        我们可以使用全局对象session来管理用户会话。Sesison 是建立在 Cookie 技术上的,不过在 Flask 中,我们还可以为 Session 指定密钥,这样存储在 Cookie 中的信息就会被加密,从而更加安全。

    复制代码
    from flask import Flask, session, redirect, url_for, escape, request
    
    app = Flask(__name__)
    app.secret_key = 'qwertyuiop'
    @app.route('/')
    def index():
        if 'username' in session:
            return 'Logged in as %s' % escape(session['username'])
        return 'You are not logged in'
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            session['username'] = request.form['username']
            return redirect(url_for('index'))
        return '''
            <form method="post">
                <p><input type=text name=username>
                <p><input type=submit value=Login>
            </form>
        '''
    @app.route('/logout')
    def logout():
        # remove the username from the session if it's there
        session.pop('username', None)
        return redirect(url_for('index'))
    复制代码

    Blueprint

      - 目录结构划分
      - 前缀
      - 特殊装饰

    - 某一类url添加前缀url_prefix
    @h.route('',methods=[],url_prefix='')
    - 给一类url添加before_request

    特殊装饰器

    app.before_request 修饰器在开发中用处非常大,比如判断某个ip是否有恶意访问行为,从而进行拦截等操作。

    app.after_request 修饰器是在用户请求得到函数响应后被执行,不过需要注意的是这个执行是在函数返回数据前被调用,即请求已经被app.route修饰的函数响应过了,已经形成了response,但还未返回给用户的时候,调用的。

    复制代码
    from flask import Flask, Request, render_template
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    @app.before_first_request  #第1个请求到来执行
    def before_first_request():
        print('before_first_request')
    
    
    @app.before_request     #在进入视图前执行
    def before_request():
       if request.path=='/login':
          return None    if session['user']:
          return None
       return redirect('/login') 
       @app.errorhandler(404) def page_not_found(error): return 'This page does not exist', 404 @app.route('/index') def index(): return "Hello World" @app.after_request #视图之后执行 def after_request1(response): print('after_request1', response) return response @app.after_request #先执行 after_request2 def after_request2(response): print('after_request2', response) return response if __name__ == '__main__': app.run()
    复制代码

    模板

      使用方式和Django的模板渲染类似:{{ }} 和 {% %}。

      基本方法不太一样,函数需要加括号执行,类似于python的语法:

        - {{ dict.get() }} 或 {{ dict["key"] }}

        - {{ list[0] }}

        - {% for 循环 %} {% endfor %}

        - {% if 判断 %} {% endif %}

      还可以自定义全局函数,在模板中使用:

    复制代码
    @app.template_global()
    def sum(a1, a2):
        return a1 + a2
    # 模板中使用{{ sum(2, 3) }}
    
    # 类似的
    @app.template_filter()
    def sum(a1, a2, a3):
        return a1 + a2 + a3
    # 调用方式不同{{ 1|sum(2,3) }}   
    复制代码

      模板继承:

    复制代码
    {% extends "base.html"%}
    
    {% block content %}
        自定义内容
    {% endblock %}
    
    {% include "组件.html" %}    
    复制代码

      定义宏:

    复制代码
    {% macro input(name, type='text', value=' ') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %}
    
    # 使用
    <form>
    {{ input('username') }}
    {{ input('password', type="password") }}
    {{ input(' ', type="submit", value="提交") }}
    </form>
    复制代码

      安全:

    复制代码
    # 前端
    {{ data|safe }}
    
    # 后端
    from flask import Markup
    data = Markup(data)
    复制代码

    Flash

      flask中暂时储存数据的一个方式

    复制代码
    from flask import flash, get_flashed_messages
    
    # 储存数据
    flash("临时数据", "name")
    
    # 获取数据, 通过pop获取并移除
    msg = get_flashed_messages(category_filter=["name"])
    复制代码

    wtforms

      安装:pip3 install wtforms 

    用户登录注册示例

    1. 用户登录

    当用户登录时候,需要对用户提交的用户名和密码进行多种格式校验。如:

    用户不能为空;用户长度必须大于6;

    密码不能为空;密码长度必须大于12;密码必须包含 字母、数字、特殊字符等(自定义正则);

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from flask import Flask, render_template, request, redirect
    from wtforms import Form
    from wtforms.fields import core
    from wtforms.fields import html5
    from wtforms.fields import simple
    from wtforms import validators
    from wtforms import widgets
    
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    class LoginForm(Form):
        name = simple.StringField(
            label='用户名',
            validators=[
                validators.DataRequired(message='用户名不能为空.'),
                validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
            ],
            widget=widgets.TextInput(),
            render_kw={'class': 'form-control'}
    
        )
        pwd = simple.PasswordField(
            label='密码',
            validators=[
                validators.DataRequired(message='密码不能为空.'),
                validators.Length(min=8, message='用户名长度必须大于%(min)d'),
                validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[$@$!%*?&])[A-Za-zd$@$!%*?&]{8,}",
                                  message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
    
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
    
    
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            form = LoginForm()
            return render_template('login.html', form=form)
        else:
            form = LoginForm(formdata=request.form)
            if form.validate():
                print('用户提交数据通过格式验证,提交的值为:', form.data)
            else:
                print(form.errors)
            return render_template('login.html', form=form)
    
    if __name__ == '__main__':
        app.run()
    app
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from flask import Flask, render_template, request, redirect
    from wtforms import Form
    from wtforms.fields import core
    from wtforms.fields import html5
    from wtforms.fields import simple
    from wtforms import validators
    from wtforms import widgets
    
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    class LoginForm(Form):
        name = simple.StringField(
            label='用户名',
            validators=[
                validators.DataRequired(message='用户名不能为空.'),
                validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
            ],
            widget=widgets.TextInput(),
            render_kw={'class': 'form-control'}
    
        )
        pwd = simple.PasswordField(
            label='密码',
            validators=[
                validators.DataRequired(message='密码不能为空.'),
                validators.Length(min=8, message='用户名长度必须大于%(min)d'),
                validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[$@$!%*?&])[A-Za-zd$@$!%*?&]{8,}",
                                  message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
    
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
    
    
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'GET':
            form = LoginForm()
            return render_template('login.html', form=form)
        else:
            form = LoginForm(formdata=request.form)
            if form.validate():
                print('用户提交数据通过格式验证,提交的值为:', form.data)
            else:
                print(form.errors)
            return render_template('login.html', form=form)
    
    if __name__ == '__main__':
        app.run()
    login.html

    2.注册

    from flask import Flask, render_template, request, redirect
    from wtforms import Form
    from wtforms.fields import core
    from wtforms.fields import html5
    from wtforms.fields import simple
    from wtforms import validators
    from wtforms import widgets
    
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    
    class RegisterForm(Form):
        name = simple.StringField(
            label='用户名',
            validators=[
                validators.DataRequired()
            ],
            widget=widgets.TextInput(),
            render_kw={'class': 'form-control'},
            default='alex'
        )
    
        pwd = simple.PasswordField(
            label='密码',
            validators=[
                validators.DataRequired(message='密码不能为空.')
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
    
        pwd_confirm = simple.PasswordField(
            label='重复密码',
            validators=[
                validators.DataRequired(message='重复密码不能为空.'),
                validators.EqualTo('pwd', message="两次密码输入不一致")
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
    
        email = html5.EmailField(
            label='邮箱',
            validators=[
                validators.DataRequired(message='邮箱不能为空.'),
                validators.Email(message='邮箱格式错误')
            ],
            widget=widgets.TextInput(input_type='email'),
            render_kw={'class': 'form-control'}
        )
    
        gender = core.RadioField(
            label='性别',
            choices=(
                (1, ''),
                (2, ''),
            ),
            coerce=int
        )
        city = core.SelectField(
            label='城市',
            choices=(
                ('bj', '北京'),
                ('sh', '上海'),
            )
        )
    
        hobby = core.SelectMultipleField(
            label='爱好',
            choices=(
                (1, '篮球'),
                (2, '足球'),
            ),
            coerce=int
        )
    
        favor = core.SelectMultipleField(
            label='喜好',
            choices=(
                (1, '篮球'),
                (2, '足球'),
            ),
            widget=widgets.ListWidget(prefix_label=False),
            option_widget=widgets.CheckboxInput(),
            coerce=int,
            default=[1, 2]
        )
    
        def __init__(self, *args, **kwargs):
            super(RegisterForm, self).__init__(*args, **kwargs)
            self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球'))
    
        def validate_pwd_confirm(self, field):    #局部钩子,全局钩子为 def validate()
            """
            自定义pwd_confirm字段规则,例:与pwd字段是否一致
            :param field: 
            :return: 
            """
            # 最开始初始化时,self.data中已经有所有的值
    
            if field.data != self.data['pwd']:
                # raise validators.ValidationError("密码不一致") # 继续后续验证
                raise validators.StopValidation("密码不一致")  # 不再继续后续验证
    
    
    @app.route('/register', methods=['GET', 'POST'])
    def register():
        if request.method == 'GET':
            form = RegisterForm(data={'gender': 1})
            return render_template('register.html', form=form)
        else:
            form = RegisterForm(formdata=request.form)
            if form.validate():
                print('用户提交数据通过格式验证,提交的值为:', form.data)
            else:
                print(form.errors)
            return render_template('register.html', form=form)
    
    
    
    if __name__ == '__main__':
        app.run()
    register app
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>用户注册</h1>
    <form method="post" novalidate style="padding:0  50px">
        {% for item in form %}
        <p>{{item.label}}: {{item}} {{item.errors[0] }}</p>
        {% endfor %}
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    register.html

    flask-session组件

    在app的__init__中

    复制代码
    from flask import Flask
    from flask_session import Session
    
    # 第一步:导入并实例化SQLAlchemy
    from flask_sqlalchemy import SQLAlchemy
    db = SQLAlchemy()
    
    from .views.account import ac
    from .views.user import us
    
    from .models import *
    
    def create_app():
        app = Flask(__name__)
        app.config.from_object('settings.Config')
    
        app.register_blueprint(ac)
        app.register_blueprint(us)
    
        # Flask-Session: 第一步示例Session
        # Session(app)
    
        # 第三步:依赖app中的配置文件
        db.init_app(app)
    
        return app
    复制代码

    在settings中

    class Config(object): 
          #配置
      SESSION_TYPE = 'redis'   SESSION_REDIS = Redis(host='192.168.0.94', port='6379')
      SECRET_KEY='QWERT' #使用session,必须配置secret_key 否则会报错

     

  • 相关阅读:
    atitit.组件化事件化的编程模型--服务端控件(1)---------服务端控件与标签的关系
    atitit. 浏览器插件 控件 applet 的部署,签名总结 浏览器 插件 控件 的签名安全机制o9o
    Atitit. 解压缩zip文件 的实现最佳实践 java c# .net php
    atitit. applet 浏览器插件 控件 的环境,开发,提示总结o9o
    Atitit..文件上传组件选型and最佳实践总结(3)----断点续传控件的实现
    Atitit..文件上传组件选型and最佳实践总结(2)----断点续传
    Atitit.guice3 ioc 最佳实践 o9o
    Atitit. C# java 的api 目录封装结构映射总结
    atitit. 统计功能框架的最佳实践(1)---- on hibernate criteria
    Atitit.Hibernate中Criteria 使用总结and 关联查询 and 按照子对象查询 o9o
  • 原文地址:https://www.cnblogs.com/wzbk/p/10308178.html
Copyright © 2011-2022 走看看