Flask从入门到放弃(介绍、模版语法案例、配置文件、路由本质、CBV整体流程)

一、Flask介绍

Flask是一个使用 Python 编写的轻量级 Web 应用框架,其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助Jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。

默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。

二、Flask快速使用

安装Flask

pip install Flask

快速使用

from flask import Flask

app = Flask(__name__)		# 类实例得到一个对象

@app.route('/')				# 注册路由
def hello_world():  # put application's code here
    return 'Hello World!'

if __name__ == '__main__':
    app.run()       # 默认是host='127.0.0.1', port=5000端口

'''
	这个时候访问5000端口跟路径就能看到 Hellow World了
'''

三、Flask展示用户信息案例

app.py

from flask import Flask, request, render_template, redirect, session

app = Flask(__name__)
app.debug = True
# print(app.config)         # 拿到当前app配置
app.secret_key = 'asdadadadLIkeasda1*asd12(01231'       # 如果需要使用到session需要配置密钥否则报错

USERS = {
    
    
    1: {
    
    'name': 'Like', 'age': 21, 'gender': '男'},
    2: {
    
    'name': 'Lisa', 'age': 22, 'gender': '女'},
    3: {
    
    'name': 'Alice', 'age': 23, 'gender': '女'},
}


@app.route('/login', methods=['GET', 'POST'])
def login():  # put application's code here
    if request.method == 'GET':
        return render_template('login.html')  # 模版都需要写在templates里面 可以通过settings修改名称
    else:
        username = request.form.get('username')  # Flask取数据从form里面获取
        password = request.form.get('password')
        if username == 'Like' and password == '123':
            session['is_login'] = True
            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(" /detail/<int:id>" ,methods=['GET']) methods:允许的请求方式
        2.新手四件套:
            -返回模板:return render_template (' detail.html” , **{'user':user}) # Context跟Django不一样
            -返回重定向:return redirect('/Login')
            -返回字符串:return '字符串'
            -返回json格式:return jsonify
        3. 使用cookie---就是session,全局的,导入使用即可,必须要指定秘钥
            -放值:session[key] = value
            -取值:session.get('key')
        4.转换器:@app.route('/detail/<int:id>'), 配合视图函数写法
            def detail(id)
        5.前端Post请求 提交数据      
            request.form
        6.模版语法:兼容Django的Dtl语法, 它可以使用 V. V[''] V.get() 取值
    """

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
    <p>用户名: <input type="text" name="username"></p>
    <p>密码: <input type="password" name="password"></p>
    <p>用户名: <input type="submit" value="登录"> <span>{
    
    {
    
     errors }}</span></p>
</form>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<table>
    {
    
    % for k,v in users.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>
</body>
</html>

detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户名称:{
    
    {
    
     user.name }}</h1>       {
    
    # 支持Django中的Dtl语法 #}
<h1>用户年龄:{
    
    {
    
     user.age }}</h1>
<h1>用户性别:{
    
    {
    
     user.gender }}</h1>
</body>
</html>

在这里插入图片描述

四、Flask配置文件

Flask中的配置文件是一个flask.config.config对象(继承字典)如果不配置的话是有默认配置的

{
    
    
        'DEBUG':                                get_debug_flag(default=False),  
        'TESTING':                              False,                          
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,							
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),				
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }

修改配置文件

app.config['DEBUG'] = True						# 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
app.config.from_pyfile('python文件名称')			# 使用本地配置文件
app.config.from_envvar('环境变量名称')			# 使用环境变量里面的信息
app.config.from_json('json文件名称')				# 必须为Json格式 因为内部会执行json.loads
app.config.from_mapping({
    
    'DEBUG': True})		# 字典格式
app.config.from_object('object / path')			# python类或类的路径

五、路由系统

1)路由系统

路由的典型写法

@app.route('/detail/<int:id>', methods=['GET', 'POST'], endpoint='detail')	# int转换器
"""
	methods:  列表规定了请求方式 如果列表中没有请求方式不被允许
	endpoint: 路由别名 如果不写会被装饰的函数名作为别名 
"""

路由中的默认转换器

DEFAULT_CONVERTERS = {
    
    
	'default':          UnicodeConverter,		# 默认
    'string':           UnicodeConverter,		# 字符串
    'any':              AnyConverter,			# 任何类型
    'path':             PathConverter,			# 路径
    'int':              IntegerConverter,		# 数字
    'float':            FloatConverter,			# 小数
    'uuid':             UUIDConverter,			# asdad-asdda-asdaa
}

2)路由本质

	1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1')	# 如果没有传endpoint,这个地方就是None
	    def route(self, rule, **options):
	        # app对象	# rule= /	# options = {methods=['GET','POST'], endpoint='n1'}
	        def decorator(f):
	            endpoint = options.pop('endpoint', None)
	            self.add_url_rule(rule, endpoint, f, **options)
	            # self是Flask的对象 app:rule路由 endpoint:别名,是None 其他的打散了传入了(methods..)
	            return f
	        return decorator
	        
	2. @decorator
	    decorator(index)
	    # 加了装饰器最终,返回的还是index,只不过执行了 self.add_url_rule(rule, endpoint, f, **options)

	"""
		Flask类中的add_url_rule方法最终意思:
			rule就是装饰器传入的路径与路由
			endpoint别名
			view_func视图函数不加括号
		
		最终结论“现在不需要使用装饰器来注册路由”
		app.add_url_rule('/home', view_func=home, endpoint='home')
		...
		(最终的结果就像Django中的SimpleRouter自动生成路由 可以写多个)
	"""

3)Add_url_rule的参数

@app.route和app.add_url_rule参数:
	rule == url
	view_func == 视图函数名称
	defaluts == None 默认值 需要穿值就是 defaluts = {
    
    'K': 'v'}
	endpoint == None 名称 用于反向生成url 
	methods = None 允许请求的方式
	
	strict_slashes = None 	对url最后的/符号是否严格要求 
		# @app.route('/index', strict_slashes=False)	如果是True的话那就需要严格添加/否则匹配失败
	redirect_to = None  重定向到指定地址
		#  @app.route('/index/<int:id>', redirect_to='/home/<id>')		当访问起那么这个路径直接跳转到后面这个路径

六、Flask的CBV

1)CBV的写法

from flask import Flask
from flask.views import MethodView

app = Flask(__name__)

# @app.route('/test', methods=['GET', 'POST'])
class Test(MethodView):
    def get(self):
        return '我是Get请求'

    def post(self):
        return '我是Post请求'

app.add_url_rule('/test', view_func=Test.as_view(name='test'))

# app.add_url_rule('/login', view_func=Login.as_view(name='index'))

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

2)CBV添加装饰器

class Test(MethodView):
    decorators = ['login', 'auth']		# 在类属性中添加decorators属性列表 是按照列表顺序依次给每个方法添加装饰器
    def get(self):
        return '我是Get请求'

'''
	首先会想我们装饰器的原理
		@auth
        def view():		本质就是 view = auth(view) 当作参数传入返回函数
    
    看完源码我们就知道了 是通过for循环的给视图类添加装饰器
'''

在这里插入图片描述

3)as_view的执行流程

把源码精简一下
	def as_view(cls, name, *class_args, **class_kwargs):
	        def view(**kwargs):
	            return self.dispatch_request(**kwargs)
	        return view

    def dispatch_request(self, **kwargs):
      meth = getattr(self, request.method.lower(), None)
      return meth(**kwargs) 
	请求来了,路由匹配成功,会执行as_view内的view() 也执行了类中的self.dispatch_request....这个就跟我们Django中的CBV一样了
	然后看到self.dispatch_request中方法 ,在当前视图类中反射,请求方式的小写字符串(get,post),如果我们写了这些方法 就会去执行。

4)Login.as_view(name=‘index’) name到底有什么用?

先研究endpoint有什么用,正常的fbv,如果不写endpoint会以函数名作为别名endpoint如何设置的?
	如果endpoint为None,它把函数名作为了endpoint
      if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)	# view_func.__name__
        options["endpoint"] = endpoint		# 如果都是endpoint就会冲突

Login.as_view(name='index'),name到底有啥用
	app.add_url_rule('/login', view_func=Login.as_view('login'))
   	没有传endpoint,Login.as_view('login')是view函数的内存地址
       endpoint会以函数名作为endpoint的值,现在所有函数都是view,必须传入name,来修改调view函数的名字
       如果传了endpoint,别名以endpoint为主,如果不传endpoint,别名以name为主
       app.add_url_rule('/login', view_func=Login.as_view(name='login'),endpoint='xxx')

5)CBV中得methods作用

视图类中有个属性就是methods = ['GET', 'POST']
用来控制允许的请求方式 写了什么方法 就允许什么请求 若没有写则不能使用该方法

七、模板语法

渲染变量

<table>
    {
    
    % for k,v in users.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>

变量的循环

<body>
    <h1>用户列表</h1>
    <table>
        {
    
    % for k,v in user_dict.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>
</body>

逻辑判断

<body>
    <h1>用户列表</h1>
    <table>
        {
    
    % if name %}
          <h1>Hello {
    
    {
    
     name }}!</h1>
        {
    
    % else %}
          <h1>Hello World!</h1>
        {
    
    % endif %}
    </table>
</body>

比Django中多了可以加括号 执行函数 传参数

from flask import Flask,render_template,Markup,jsonify,make_response
app = Flask(__name__)

def func1(arg):
    return Markup("<input type='text' value='%s' />" %(arg,))
@app.route('/')
def index():
    return render_template('index.html',ff = func1)

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


index.html
		<!DOCTYPE html>
		<html lang="en">
		<head>
		    <meta charset="UTF-8">
		    <title>Title</title>
		</head>
		<body>
		
		    {
    
    {
    
    ff('六五')}}
			{
    
    {
    
    ff('六五')|safe}}
		
		</body>
		</html>

猜你喜欢

转载自blog.csdn.net/MeiJin_/article/details/128255907
今日推荐