Flask快速使用

Flask框架

介绍

flask是基于python开发并且依赖于jinjia2模板和werkzeug wsgi服务的一个微型框架
werkzeug本质是socket服务端,用于接收http请求并对其进行预处理,然后触发flask框架,开发人员基于flask框架提供的功能对请求进行相应的处理,并返回给用户,如果返回给用户复杂的内容时,需要借助于jinja2模板来实现对模板的处理。即:将模板和数据进行渲染,将渲染的字符串返回给用户浏览器

Flask的两个主要核心应用是Werkzeug和模板引擎Jinja.

快速使用
# pip install flask   【目前最高版本2.2.2】

from flask import Flask
app = Flask(__name__)  # 实例化得到对象
# 注册路由
@app.route('/')
def index():
    return 'Hello World!'
if __name__ == '__main__':
    app.run()  # 括号内可以指定地址 不写就是默认地址加端口5000
登录展示用户信息案例
from flask import Flask, request, render_template, redirect, session, jsonifyf
from flask.views import MethodView


app = Flask(__name__)
# request虽然在全局导入的 但是在哪个视图函数用就是当次请求的request


# 使用session的话必须先设置key值
app.secret_key = 'shvhcdsmghtrdhknksbvasdavbjbhva'

# 用户字典
USERS = {
    1: {'name': 'jason', 'age': 18, 'hobby': 'read'},
    2: {'name': 'kevin', 'age': 19, 'hobby': 'run'},
    3: {'name': 'tony', 'age': 20, 'hobby': 'dance'},
    4: {'name': 'jerry', 'age': 21, 'hobby': 'sing'}, }


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'summer' and password == '123':
            session['is_login'] = True  # 写入cookie
            return redirect('/index')
        else:
            return render_template('login.html', errors='用户名或密码错误')


@app.route('/index', methods=['GET'])
def index():
    if session.get('is_login'):
        return render_template('index.html', **{'users': USERS})
    else:
        return redirect('/login')


@app.route('/detail/<int:id>')
def detail(id):
    if session.get('is_login'):
        user = USERS.get(id)
        return render_template('detail.html', **{'user': user})
    else:
        return redirect('/login')


if __name__ == '__main__':
    app.run()

总结
1.注册路由:@app.route('/login',methodes=['GET','POST'])  # methods允许请求的方式
2.新手四件套:
    -返回模板信息:return render_template('index.html', **{'users': USERS}) 
     # django里面的是context,flask可以直接使用**
    -重定向:return redirect('/index')
    -返回字符串:return '字符串'
    -返回json格式:return jsonify
3.使用session 【全局使用,必须指定密钥】
 app.secret_key = 'shvhcdsmghtrdhknksbvasdavbjbhva'
 -设置值:session['key'] = value
  eg: session['is_login'] = True  # 写入cookie/session
 -获取session:session.get('key')
4.转换器使用:
   @app.route('/detail/<int:id>')  # 直接在路由里配置 int后面的参数必须写在函数括号内
   def detail(id):
      pass
5.获取post请求的数据:
  request.form
6.模板语法:使用的jinjia2【可以采用字典取值的方式,也可以直接点取值】
 eg:{{v.name}} / {{v.get('name')}}/ {{v.['name']}} 
配置文件
# flask的默认配置文件在app.config
【重要参数】
     1:DEBUG:是否是调试模式
     2:SECRET_KEY:项目密钥
     3:SESSION_COOKIE_NAME:默认为session 可以自己指定
        
'''配置文件配置的多种方式'''  【最后都是写到了app.config中】
1. 直接使用app.debug = True 
2. 通过app.config配置 
   app.config['DEBUG'] = True   # config是个字典
3. 通过配置文件配置 【和django很像】
   - 写一个settings.py,里面的配置名也是大写  
      DEBUG = True
   - 将配置文件映射到config中,后期使用自己写的配置
     app.config.from_pyfile('settings.py')  【括号内写配置文件的名称】
4. 通过类配置 【最常用的(上线和测试都可用)】
   - 写一个setting.py ,将所有的配置以类的形式写在配置文件中
        class Config(object):
            DEBUG = False
            TESTING = False
            DATABASE_URI = 'sqlite://:memory:'  # 自定义的配置

        class ProductionConfig(Config):
            DEBUG = False
            DATABASE_URI = 'mysql://192.168.11.11/foo'  # 上线数据库地址

        class DevelopmentConfig(Config):
            DEBUG = True
            DATABASE_URI = 'mysql://127.0.0.1/foo'  # 开发阶段本地数据库地址

   - app.config.from_object('setting.DevelopmentConfig')  # 测试阶段使用的配置类
   - app.config.from_object('setting.ProductionConfig')   # 上线使用的配置类

5.其他配置类型  
   - app.config.from_envvar('环境变量名称')  # 写入到环境变量中
   - app.config.from_json('json文件名称')  # 配置直接写在json文件中
   - app.config.from_mapping({'DEBUG':True}) # 配置直接从字典中映射过来
  
'''拓展芝士'''
# 分布式配置中心 【nocos,Apollo】
将分布式项目的配置单独写在一个分布式配置中心,以后如果需要修改配置文件信息直接在配置中心修改即可,不需要再去项目中一个个修改配置文件
    获取分布式配置中心的配置: res = requests.get('配置中心的地址').json()
    由于配置文件拉取下来在项目中是json格式,那么可以使用到下面的配置方式
    app.config.from_mapping(res)  # 将配置映射到项目中
路由系统
# 在flask中是以装饰器的形式写路由的
app.route('/login'<int:pk>,methods=['GET','POST']) 可以使用转换器/请求方式/路由别名
- 比较重要的几个转换器:string/path/int
- methods:规定的请求方式,只有写了才可以使用
- endpoint:路由的别名【如果路由重名的情况下,可以使用别名】
路由系统本质【部分源码分析】
# flask路由的本质是app对象的方法self.add_url_rule(rule,endpoint,f,**options)
@app.route('/login') 
def login:
    pass

装饰器的本质是:index=app.route('/login')(index)
   def route(self, rule, **options):
    # 1.login执行了@app.route('/login'),返回的是decorator,@app.route('/')(index)=@decorator(index)
        def decorator(f):
         # 此时的f就是index函数
            endpoint = options.pop("endpoint", None)
         # 2.self就是flask的对象app 执行了add_url_rule方法 返回了index 
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator
    def add_url_rule(self,rule,endpoint,view_func,**options):
        # 3.主要看add_url_rule方法的参数
        pass
    
    1.rule 路由 /login
    2.endpoint 别名,没写就把函数名当作别名
    3.view_func 视图函数不加括号 login
    4.**options 可以将methods等参数打散传入
   
# 通过源码分析,路由地址可以写成以下方式
 app.add_url_rule('/login',view_func=login)
add_url_rule的其他参数(使用频率不高)
1. defaults=None 当url中没有参数,函数需要传参数时,使用defaults={'k':'v'} 【类似于django路由中的kwargs】 
eg: @app.route('/login',defaults={'name':'summer'})
    def login(name):
        pass
2. strict_slashes=None 对url后面的/是否必须要
eg: @app.route('/login',strict_slashes=False)  # 如果是True的话就不能加/
    访问路由:http://127.0.0.1:5000/index 和 http://127.0.0.1:5000/index/ 都可以
                    
3. redirect_to=None 重定向到指定地址
eg:  @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
cbv的写法
from flask.views import MethodView
class Login(MethodView):
    decorators = [] 
    def get(self):
       return ''
    def post(self):
        return ''

# 路由写法 【as_view必须传值,传的值是别名】
app.add_url_rule('/login',view_func=Login.as_view('userlogin'))
# cbv加装饰器的话 直接写一个参数即可 列表内可写多个
decorators = [] 

# 装饰器部分源码解读
def as_view(cls, name,*class_args, **class_kwargs) 
    if cls.decorators:  # 如果decorators有值的话
        for decorator in cls.decorators: # 循环执行列表里的装饰器
            view = decorator(view)  # 给视图类中的方法加装饰器 
        return view
     
cbv源码分析
# as_view()的执行流程
  def as_view(cls, name,*class_args, **class_kwargs) 
      def view(**kwargs):
             return self.dispatch_request(**kwargs)
      return view

1.执行as_view(),返回了view,其实是执行了view(**kwargs),而view函数内又执行了self.dispatch_request
  self就是当前视图类的对象 【也就是执行的的MethodView里的dispatch_request】
    
 def dispatch_request(self, **kwargs):
        meth = getattr(self, request.method.lower(), None)
        if meth is None and request.method == "HEAD":
            meth = getattr(self, "get", None)
        return meth(**kwargs)

2.当请求来了,获取当前的类里面的小写方法get,此时的返回的meth是视图类中的get方法
endpoint相关源码分析
# 视图函数的路由装饰器参数endpoint

   def add_url_rule(self,rule,endpoint:None,view_func:None,**options):
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func) 
        options["endpoint"] = endpoint
  '''
  flask里的add_url_rule方法的参数endpoint默认为None,
  当endpoint是None的时候,执行了_endpoint_from_view_func(view_func)把当前的视图函数当作参数
  '''
    def _endpoint_from_view_func(view_func):
        assert view_func is not None,  
        return view_func.__name__
   '''
    assert断言该函数不为空
    如果不为空的话返回了view_func.__name__  
    __name__就是当前函数的名字
    也就是说 当endpoint为None的时候,会默认将函数名当作别名
   '''
# view_func=Login.as_view(name='login') 括号里的就是别名,相当于endpoint
 由于as_view()执行的是view的内存地址 
 endpoint又没有传值,那么就将函数的名字当作别名,但是as_view()返回的都是view,没法区分,就必须要写name
 as_view()又必须传值,那么如果没有endpoint以name为值,如果传了endpoint就以endpoint的值为值
继承view写cbv
1.执行流程和MethodView是一样的
2.路由匹配成功执行self.dispatch_request
3.view里的self.dispatch_request是直接抛异常的 
4.如果想要继承view写cbv的话,必须重写self.dispatch_request方法 
  【MethodView就是重写了self.dispatch_request】
模板语法
from flask import Flask, render_template,Markup
app = Flask(__name__)
@app.route('/')
def index():
    # return render_template('test.html', name='lqz', age=19)
    # return render_template('test.html',
    #                        user={
    #                            1: {'name': 'lqz', 'age': 19, 'hobby': '篮球'},
    #                            2: {'name': 'lqz1', 'age': 20, 'hobby': '橄榄球'},
    #                            3: {'name': 'lqz2', 'age': 21, 'hobby': '乒乓球'},
    #                        })

    a='<a href="http://www.baidu.com">点我看美女</a>'
    # a=Markup(a)    直接在后端就写好safe   
    return render_template('test.html',a=a)
if __name__ == '__main__':
    app.run()
<body>
{#{{ name }}---{{ age }}#}


{#<table>#}
{#    {% for k,v in user.items() %}#}
{#        <tr>#}
{#            <td>{{ k }}</td>#}
{#            <td>{{ v.name }}</td>#}
{#            <td>{{ v['name'] }}</td>#}
{#            <td>{{ v.get('name') }}</td>#}
{#            <td><a href="/detail/{{ k }}">查看详细</a></td>#}
{#        </tr>#}
{#    {% endfor %}#}
{#</table>#}


{#<table>#}
{#    {% if name %}#}
{#        <h1>Hello {{ name }}!</h1>#}
{#    {% else %}#}
{#        <h1>Hello World!</h1>#}
{#    {% endif %}#}
{#</table>#}


{#{{ a|safe }}#}
{{ a}}


</body>
</html>
posted @ 2022-12-11 20:36  Hsummer  阅读(65)  评论(0编辑  收藏  举报