Flask from entry to abandonment (introduction, template syntax case, configuration file, routing essence, CBV overall process)

1. Introduction to Flask

Flask is a lightweight web application framework written in Python, its WSGI toolbox uses Werkzeug, and its template engine uses Jinja2. For Werkzeug, the essence is the Socket server, which is used to receive http requests and preprocess the requests, and then trigger the Flask framework. The developer processes the requests based on the functions provided by the Flask framework and returns them to the user. If you want to return to When users have complex content, they need to use Jinja2 templates to process the templates, that is, render the templates and data, and return the rendered strings to the user's browser.

"Micro" doesn't mean that you need to cram your entire web application into a single Python file (although you can), nor does it mean that Flask is lacking in functionality. The "micro" in microframework means that Flask aims to keep the core simple and easy to extend. Flask doesn't make many decisions for you - like which database to use. Those chosen by Flask - such as which templating engine to use - are easy to replace. Everything else is in your hands. In this way, Flask can be a perfect match for you.

By default, Flask doesn't include a database abstraction layer, form validation, or anything else that various libraries already do. However, Flask supports extensions to add these features to the application, just as Flask itself does. Numerous extensions provide functionality such as database integration, form validation, upload handling, various open authentication techniques, and more. Flask may be "tiny", but it's ready to go in production with heavy demands.

Two, Flask quick use

Install Flask

pip install Flask

quick use

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了
'''

Three, Flask display user information case

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>

insert image description here

4. Flask configuration file

The configuration file in Flask is a flask.config.config object (inheritance dictionary). If not configured, there is a default configuration

{
    
    
        '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,
    }

Modify the configuration file

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类或类的路径

5. Routing system

1) Routing system

Typical way of writing routing

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

default converter in routing

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

2) Routing essence

	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) Parameters of 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>')		当访问起那么这个路径直接跳转到后面这个路径

6. Flask's CBV

1) How to write 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) Add decorator to CBV

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

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

insert image description here

3) Execution process of 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) What is the use of 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) The role of methods in CBV

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

7. Template syntax

render variable

<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>

variable loop

<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>

logical judgment

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

More than in Django, you can add parentheses to execute function parameters

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>

Guess you like

Origin blog.csdn.net/MeiJin_/article/details/128255907