Flask——类视图

类视图

1-类和视图

​ 之前我们接触的视图都是函数,所有我们一般简称视图函数。其实视图也可以基于类来实现,类视图的好处是支持继承,但是类视图不能跟函数视图一样,写完类视图还需要通过app.add_rulue(url_rule,view_func)来进行注册。以下将对两个类视图进行讲解:

标准类视图

​ 标准类视图是继承自flask.views.View,并且在子类中必须实现dispatch_request方法,这个方法类似于视图函数,也要返回一个基于Response或者其子类的对象。

# -*- coding: utf-8 -*- 
# @Time : 2020/4/16 14:32 
# @Author : 大数据小J
from flask import Flask, url_for, views

app = Flask(__name__)


@app.route('/')
def hello_world():
    # 如果add_url_rule给了endpoint,相当于给url起了一个新的名字,就不能访问函数名
    print(url_for('core'))     # 函数名
    print(url_for('View'))     # 当创建标准类视图的时候,可以从as_view中通过name属性来读取到值
    return 'Hell world'


def index():
    return '个人中心'


# 当继承标准的类视图之后,dispatch_request这个方法必须重写
class ListView(views.View):
    # 该方法一定要重写
    def dispatch_request(self):
        # self.demo()
        # 当类中可以通过方法来进行调用
        return self.demo()

    def demo(self):
        return 'demo'


# rule必须传  rule 代表着路由的规则
# add_url_rule为新的传递路由的一个规则
app.add_url_rule('/index/', endpoint='core', view_func=index)
app.add_url_rule('/views/', view_func=ListView.as_view('View'))

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

类重写的方式来返回json

# -*- coding: utf-8 -*- 
# @Time : 2020/4/16 15:25 
# @Author : 大数据小J

from flask import Flask, views, jsonify

app = Flask(__name__)


# 创建一个标准类视图
class Jsonview(views.View):

    # 用类的方式重写get_response,当类继承的时候,不重写之个方法就会主动抛出异常
    def get_response(self):
        raise NotImplementedError

    def dispatch_request(self):
        response = self.get_response()
        return jsonify(response)


class Listview(Jsonview):

    def get_response(self):
        return {'username': 'SmallJ'}

# 添加url路由的规则
app.add_url_rule('/', view_func=Listview.as_view('json_data'))

if __name__ == '__main__':
    app.run(debug=True, port=8787)	
    

通过公共类来实现参数传递

# -*- coding: utf-8 -*- 
# @Time : 2020/4/16 15:52 
# @Author : 大数据小J

from flask import Flask, views, render_template

app = Flask(__name__)


# 把公共的功能放在一个类中进行继承处理
# 该类为公共继承
class public_views(views.View):
    def __init__(self):
        self.context = {
            'username': 'SmallJ'
        }
        super(public_views, self).__init__()


# 注册页面
class register(public_views):
    def dispatch_request(self):
        return render_template('register.html', **self.context)


# 登录页面
class Sign_in(public_views):
    def dispatch_request(self):
        return render_template('Sign_in.html', **self.context)


# URL规则
app.add_url_rule('/register/', view_func=register.as_view('register'))
app.add_url_rule('/Sign_in/', view_func=Sign_in.as_view('Sign_in'))

if __name__ == '__main__':
    app.run(debug=True, port=5555)

基于调度方法的视图

​ Flask还为我们提供了另外一种类视图flask.views.MethodView,对每个HTTP方法执行不同的函数(映射到对应方法的小写的同名方法上)

  • 基于方法的类视图,是根据请求的method来执行不同的方法的。

  • 如果用户是发送的get请求,那么将会执行这个类的get方法。

  • 如果用户发送的是post请求,那么将会执行这个类的post方法。

  • 其他的method类似,比如delete,put

  • 这种方式可以让代码更加简洁

  • 所有和get请求相关的代码都放到get方法中,所有和POST请求相关代码都放在POST方法中。

  • 就不需要通过requests.method == 'GET'

    from flask import Flask, render_template, views, request
    
    app = Flask(__name__)
    
    
    class LoginView(views.MethodView):
        def __render(self, error=None):
            return render_template('login.html', error=error)
    
        def get(self):
            return self.__render()
    
        def post(self):
            username = request.form.get('username')
            password = request.form.get('password')
            return '登录成功' if username == 'SmallJ' and password == '123' else self.__render(error='用户名或密码错误')
    
    
    app.add_url_rule('/login/', view_func=LoginView.as_view('login'))
    
    if __name__ == '__main__':
        app.run(debug=True, por	t=6789)
    

POST请求结果

在这里插入图片描述

GET请求结果

2-蓝图

​ 之前我们写的url和视图函数都是处在同一个文件,如果项目比较大的话,这显然表示一个合理的结构,而蓝图可以优雅的帮我们实现这种需求,在开发项目中,我们经常会使用到蓝图来进行管理系统。

​ 简单来说,Blueprint是一个存储视图方法的容器,这些操作在这个Blueprint被注册到一个应用之后就可以被调用,Flask可以通过Blueprint来组织URL以及处理请求。

​ Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性:

  • 一个项目可以具有多个Blueprint
  • 可以将一个Blueprint注册到任何一个未使用的的URL比如"/"、"/sample/" 或者子域名
  • 在一个应用中,一个模块可以注册多次
  • Blueprint可以单独具有自己的模板、静态文件或者其它的通过操作方法,它并不是必须要实现应用的视图和函数

使用蓝图的好处

​ 方便代码的维护,开发项目进行分工合作。

蓝图的运行机制

  • 蓝图是保存了一组将来可以应用对象上执行的操作,注册路由就是一种操作
  • 当在app对象上调用route装饰器注册路由时,这个操作将修改对象的url_map路由表
  • 当我们在蓝图上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加一个项
  • 当执行app对象的register_blueprint()方法时,应用对象将从蓝图对象的defered_functions列表中取出每一项,并以自身作为参数执行该匿名函数。

蓝图URL前缀

​ 当我们在应用对象上注册一个蓝图时,可以指定一个url_prefix关键字参数(这个参数默认是“/”)

# -*- coding: utf-8 -*- 
# @Time : 2020/4/17 14:56 
# @Author : 大数据小J
from flask import Flask
from blueprints.news import new_bp


app = Flask(__name__)
# 注册蓝图
app.register_blueprint(new_bp)


@app.route('/')
def hello_world():
    return '首页'


if __name__ == '__main__':
    app.run(debug=True,port=4567)



# -*- coding: utf-8 -*- 
# @Time : 2020/4/17 15:00 
# @Author : 大数据小J
from flask import Blueprint

# Blueprint中默认要传递两个参数
# name :为蓝图的名字
# import_name : __name__   当前.py文件名字
new_bp = Blueprint('news', __name__)


@new_bp.route('/new/')
def news():
    return '这是新闻页'

在这里插入图片描述

在这里插入图片描述

flask_blue.py

# -*- coding: utf-8 -*- 
# @Time : 2020/4/17 14:56 
# @Author : 大数据小J
from flask import Flask
from blueprints.news import new_bp
from blueprints.movies import movie_bp

app = Flask(__name__)
# 注册蓝图
app.register_blueprint(new_bp)
app.register_blueprint(movie_bp)


@app.route('/')
def hello_world():
    return '首页'


if __name__ == '__main__':
    app.run(debug=True, port=4567)



news.py

# -*- coding: utf-8 -*- 
# @Time : 2020/4/17 15:00 
# @Author : 大数据小J
from flask import Blueprint

# Blueprint中默认要传递两个参数
# name :
# import_name : 为当前的文件夹的名字
# url_prefix : 为动态URL前缀
new_bp = Blueprint('news', __name__, url_prefix='/new/')


@new_bp.route('/')
def news():
    return '这是新闻页'


@new_bp.route('/detail/<int:bid>/')
def new_page(bid):
    return '这是新闻的第 %d 页' % bid

movies.py

# -*- coding: utf-8 -*-
# @Time : 2020/4/17 15:01
# @Author : 大数据小J

from flask import Blueprint

movie_bp = Blueprint('movie', __name__, url_prefix='/movie/')


@movie_bp.route('/')
def movie():
    return '这是电影首页'


@movie_bp.route('/page/<int:aid>/')
def movie_page(aid):
    return '这是电影的第 %d 页' % aid

设置蓝图中模板的目录

​ 蓝图对象默认的模板目录为系统的模板目录,可以在创建蓝图对象时使用template_folder关键字参数设置模板目录

  • template_folder存在,会在传递了指定文件目录的时候,会去当前目录下寻找该模板文件
  • template_folder不存在的话,会去templates文件夹目录下寻找该相对应的模板文件
  • 注意:如果在templates中存在和lgion文件中有相同的.html文件的话,系统会优先级寻找templates中的html
# -*- coding: utf-8 -*- 
# @Time : 2020/4/17 15:00 
# @Author : 大数据小J
from flask import Blueprint, render_template

# Blueprint中默认要传递两个参数
# name :
# import_name : 为当前的文件夹的名字
# url_prefix : 为动态URL前缀
new_bp = Blueprint('news', __name__, url_prefix='/new/', template_folder='lgion')


@new_bp.route('/')
def news():
    # return '这是新闻页'
    return render_template('index.html')

@new_bp.route('/detail/<int:bid>/')
def new_page(bid):
    return '这是新闻的第 %d 页' % bid
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>这是蓝图中的模板文件</h1>
</body>
</html>

注册蓝图中的静态文件的相关路由

  • 和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在创建时指定static_folder参数。

  • 默认不设置任何静态文件路径,Jinja2会在项目的static文件夹中寻找静态文件,也可以设置其他的路径,在初始化蓝图的时候,Blueprint这个构造函数,有一个参数staric_folder可以指定静态文件的路径。

  • static_folderk可以是相对路径(相对蓝图文件所在的目录),也可以是绝对路径。在配置完蓝图后,还有一个需要注意的地方是如何在模板中引用静态文件。在模板中引用蓝图,应该要使用蓝图名+.+static来引用

news.py

# -*- coding: utf-8 -*- 
# @Time : 2020/4/17 15:00 
# @Author : 大数据小J
from flask import Blueprint, render_template

# Blueprint中默认要传递两个参数
# name :
# import_name : 为当前的文件夹的名字
# url_prefix : 为动态URL前缀
new_bp = Blueprint('news', __name__, url_prefix='/new/', template_folder='lgion', static_folder='static')


@new_bp.route('/')
def news():
    # return '这是新闻页'
    return render_template('index.html')

@new_bp.route('/detail/<int:bid>/')
def new_page(bid):
    return '这是新闻的第 %d 页' % bid

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for('news.static', filename='new.css') }}">
</head>
<body>
    <h1>这是蓝图中的模板文件</h1>

</body>
</html>

在这里插入图片描述

寻找静态文件

​ 跟静态文件一样,默认不设置任何模块文件路径,将会在项目的templates中寻找模板文件。也可以设置其他的路径,在构建函数Blueprint中有一个template_folder参数可以设置模板的路径

bp = Blueprint('news', __name__, url_prefix='/new/', template_folder='lgion', static_folder='static')

​ 模板文件和静态文件有点区别,以上代码写完以后,如果你渲染应该模板return render_template('[...].html'),Flask默认会去项目根目录下的templates文件夹中查找该.html文件,如果找到了就直接返回,如果没有找到,才会去蓝图文件所在的目录下的templates文件夹中寻找。

url_for生成url

url_for生成蓝图的url,使用的格式是:蓝图的名称+视图函数名称

在这里插入图片描述

3- 子域名

什么是子域名

​ 子域名,类似于xxx.douban.com的形式,如book.douban.com, music.douban.com, movie.douban.com等

用Flask怎么实现子域名

​ flask在注册路由的时候,允许一个参数subdomain

​ 子域名在许多网站中都用到了,比如一个网站叫做xxx.com,那么我们可以定义一个子域名cms.xxx.com来作为cms管理系统的网址,子域名的实现一般也是通过蓝图来实现,在之前章节中,我们创建蓝图的时候添加了一个url_prefix=/user作为url前缀,那样我们就可以通过/user/来访问user下的url。但使用子域名则不需要。另外,还需要配置SERVER_NAME

​ 比如app.config[SERVER_NAME]='example.com:9000'。并且在注册蓝图的时候,还需要添加一个subdomain的参数,这个参数就是子域名的名称

from flask import Blueprint
bp = Blueprint('admin',__name__,subdomain='admin')
@bp.route('/')
def admin():
    return 'Admin Page'

这个没有多大区别,接下来看主app的实现

from flask import Flask
import admin
# 配置`SERVER_NAME`
app.config['SERVER_NAME'] = 'example.com:8000'
# 注册蓝图,指定了subdomain
app.register_blueprint(admin.bp)
if __name__ == '__main__':
    app.run(host='0.0.0.0',port=8000,debug=True)

写完以上两个文件后,还是不能正常的访问admin.example.com:8000这个子域名,因为我们没有在host文件中添加域名解析,你可以在最后添加一行127.0.0.1 admin.example.com,就可以访问到了。另外,子域名不能在127.0.0.1上出现,也不能在localhost上出现。

猜你喜欢

转载自blog.csdn.net/qq_37662827/article/details/105687532