Flask(1):基本示例、配置文件、路由、请求和响应、模板渲染
Flask的特点:
- pip install flask - 短小精悍、可扩展性强的 web框架 注意:上下文管理机制 - 依赖 wsgi:werkzeug
Flask的简单示例:
from flask import Flask # app = Flask(__name__,template_folder="templates",static_folder="static",static_url_path="/vvv") # template_folder(默认为 templates )、static_folder(默认为static)都是在这里设置;static_url_path="/vvv":设置静态文件的路径(给静态文件statci的路径设置一个别名;用在模板中) app = Flask(__name__) @app.route("/index") # 装饰器表示 路径和函数 绑定 def index(): return "hello world" if __name__ == "__main__": app.run() # 启动 socket
Flask登陆示例:
目录结构:
project
|-- static
|-- 1.png
|-- templates
|-- index.txt
|-- login.html
|-- flask_login.py
flask_login.py
from flask import Flask,request,render_template,redirect,session app = Flask(__name__) app.secret_key = "nbaoireunbadfo" # 设置session的时候,需要加盐加密 @app.route("/login",methods=["GET","POST"]) def login(): if request.method == "GET": return render_template("login.html") username = request.form.get("username") password = request.form.get("psw") if username == "neo" and password == "abc123": session["user"] = username # 设置 session return redirect("/index") else: return render_template("login.html", error="用户名密码错误") # 传递参数也可用字典 @app.route("/index") def index(): # 登陆之后才能访问 index 页面 if not session.get("user"): # 获取 session return redirect("/login") return render_template("index.txt") # 模板后缀不影响 if __name__ == "__main__": app.run() """ 小结: from flask import request # Flask 的请求数据是这样导入的,不是像Django 那样通过参数传递的 from flask import render_template # 渲染的模板 render_template(模板名,**{"传递的参数":传递的参数}) from flask import redirect # 重定向 from flask import session # session;flask中session默认是以加密的方式保存在了用户浏览器的cookie中;所以要设置加盐(加密) app.secret_key = "apiofdgqpweu" # session 加密加盐 request.methods # 获取请求方式 request.args # 获取 GET 请求的数据,对应 Django 的request.GET (url里面传过来的参数) request.form # 获取 POST 提交过来的数据,对应Django的 request.POST(请求体里面传过来的参数) @app.route("/login",methods=["GET","POST"]) # methods=["GET","POST"] 表示可接收GET和POST请求,默认只接收GET # 默认的 模板文件夹叫 templates;默认的静态文件叫 static # <form>表单只能发送 get 和 post请求,patch 和 delete请求要通过 Ajax发送 """
templates/index.txt
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>欢迎登陆</h3> <img src="/static/1.png" alt=""> # src 中的 /static 可更改,通过 static_url_path 设置 </body> </html>
templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> <input type="text" name="username"> <input type="password" name="psw"> <input type="submit" value="提交"> <span>{{error}}</span> <!-- {{ }} 用于传递参数 --> </form> </body> </html>
配置文件:
# 通过字符串找到类中的静态字段,如 "settings.Foo" 中的静态字段
# 通过字符串找到类中的静态字段,如 "settings.Foo" 中的静态字段 import importlib path = "settings.Foo" module_path,class_name = path.rsplit(".",1) module = importlib.import_module(module_path) cls = getattr(module,class_name) for key in dir(cls): # dir(cls) :返回一个列表,其中包含静态字段 if key.isupper(): # 静态字段得是大写 print(key,getattr(cls,key)) # 获取静态字段及对应的值
设置配置文件:
# settings.py class Config(object): 共用的配置信息 TESTING = False class ProductionConfig(Config): 生产环境下的配置 DEBUG = False class DevelopmentConfig(Config): DEBUG = True # app.py from flask import Flask app = Flask(__name__) # app.config # 获取 Flask 的 配置文件 # 配置文件中的字段必须得是 全大写 # app.config.from_object("python类或类的路径") # 设置配置文件 # 也可以这样单独设置配置信息: # app.config["DEBUG"] = True app.config.from_object("settings.DevelopmentConfig") if __name__ == "__main__": app.run()
其它配置:
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为: { 'DEBUG': get_debug_flag(default=False), 是否开启Debug模式 'TESTING': False, 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, # session 相关(加盐加密) '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.route() 这个路由中的参数 endpoint="xx" :给该视图函数起一个别名(相当于django url中的name),如果 endpoint不写,默认是函数名;通过别名反解路径: url_for("xx") , url_for 需要导入 # 路由的动态传参 @app.route("/index/<int:nid>",method=["GET","POST"],endpoint="url1") # 路由中传参时,视图函数中需要接收一下;如果 int 不写,则默认是字符串格式; def index(nid): # 接收参数 print(url_for("url1",nid=777)) # 反解路径时,如果url中动态传参了,需要在后面指定传的参数 return "Index" # 动态传参时的类型包括:string,int,float 和 path; 如果不指定,默认是 string
请求和响应
from flask import Flask,request,render_template,redirect,make_response # ...(省略) @app.route("/login",methods=["GET","POST"]) def login(): """ 请求相关信息: request.method request.args request.form request.values request.cookies request.headers request.path # 请求的路径 request.full_path request.script_root request.url request.base_url request.url_root request.host_url request.host request.files # 文件 obj = request.files['the_file_name'] obj.save('/var/www/uploads/' + secure_filename(obj.filename)) # 保存文件 """ """ 响应相关信息: 1. 响应体: return "字符串" return jsonify(xxx) # 返回 json 数据; jsonify 需要从 flask导入 return render_template(模板) return redirect() # 重定向 上面4个返回的都是响应体(都是以响应体的方式返回) 2. 定制响应头(以 return "字符串" 为例): obj = make_response("Index") # make_response(你想要返回的内容); make_response() 能把你想要返回的内容进行封装到一个对象中; make_response 需要从 flask导入 obj.headers["xxx"] = "abc" # 设置响应头 return obj # 返回响应对象 3. 设置 cookie obj = make_response(render_template("index.html")) obj.set_cookie("key","value") # 设置cookie # cookie 是随着响应头给用户的 obj.delete_cookie("key") # 删除 cookie return obj """ # ...(省略)
模板渲染
python代码:
# 下面的字典模拟数据库 STU_DICT = { 1:{"name":"neo","age":22,"gender","male"}, 2:{"name":"maple","age":35,"gender","male"}, 3:{"name":"conan","age":12,"gender","male"}, } # index 函数 @app.route("/index") def index(): return render_template("index.html",stu_dict=STU_DICT) # 渲染模板时,传入要渲染的参数
对应的模板:
<table> <thead> <tr> <th>ID</th> <th>姓名</th> <th>年龄</th> <th>性别</th> </tr> </thead> <tbody> <!-- Flask 渲染模板时,用到的python函数需要加括号“()”;Django不需要 --> {% for k,v in stu_dict.items() %} <tr>{{k}}</tr> <!-- 可以用 .name 的方式 来取值;和Django的用法一样 --> <tr>{{v.name}}</tr> <!-- 可以用 v["age"] 的这种字典的方式 来取值 --> <tr>{{v["age"]}}</tr> <!-- 也可以用 v.get("gender","female") 的这种字典的方式 来取值; .get() 的时候也可设置默认值 --> <tr>{{v.get("gender")}}</tr> {% endfor %} </tbody> </table>
其它模板渲染的方法:
tpl_render.py
from flask import Flask,render_template,Markup app = Flask(__name__) def func(arg): return arg + 1 @app.template_global() # 如果某个函数在全局好多模板中都需要用到,为了避免多次传递这个函数,可以使用template_global()这个装饰器装饰该函数(该装饰器需要加() ),然后这个函数就能在全局所有模板中直接使用 def foo_global(a,b): # 使用方法:{{foo_global(2,3)}} return a + b @app.template_filter() # template_filter() 装饰的函数也能在全局(该装饰器需要加 ()),只是这个被装饰的函数 能用在前端的 if等语句中 def foo_filter(a,b,c): # 使用方法: return a + b + c @app.route("/tpl") def tpl(): context = { "user":["neo","maple"], "txt1":'<input type="text">', "txt2": '<input type="text">', "txt3": Markup('<input type="text">'), # HTML标签字符串也可以在后端 Markup(),从而让其在前端展示为 HTML标签 "func":func, # 也可以往前端传递一个函数;Flask传递函数时在前端不会自动执行,得自己调用(Django传递函数会自动执行) } return render_template("tpl.html",**context) # 可以通过 **context 的方式传参 if __name__ == "__main__": app.run()
tpl.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 和Django的用法一样,Flask也可以:list.索引;user是["neo","maple"]这个列表 --> {{user.0}} <!-- python语法也能在 Flask 中直接用:list[索引] --> {{user[0]}} <!-- {{txt1}}是字符串;Flask自动将 html 标签字符串做了处理 --> {{txt1}} <!-- 如果想让 HTML 标签字符串 变成HTML标签,可以在前端 |safe --> {{txt2|safe}} <!-- HTML标签字符串也可以在后端 Markup(),从而让其在前端展示为 HTML标签 --> {{txt3}} <!--传递函数--> {{func(2)}} <!-- template_global() 装饰的函数能在全局模板直接使用 --> {{foo_global(2,3)}} <!-- template_global() 装饰的函数能在全局模板直接使用,{{1|foo_filter(2,3)}} :a是1,b是2,c为3 --> {{1|foo_filter(2,3)}} <!--宏定义--> <!-- macro 是宏定义的语法(相当于函数定义的 def );input是宏定义的函数名(可随便改);type="text"表示type默认为"text",value="" 表示 value默认为空 --> {% macro input(name,type="text",value="") %} <h2>宏定义</h2> <input type="{{type}}" name="{{name}}" value="{{value}}"> {% endmacro %} <!--宏定义的函数不会自动执行,需要调用,如下--> {{input("neo")}} <!-- 此外, Flask 的 模板继承 和 include 的使用方法 和 Django 一样,不再重复 --> </body> </html>
Code your future.