python web之flask学习(三)

经过上一节,对url有一定了解,这一节学习静态文件管理、视图、模板(jiaja2)

一、静态文件管理

web应用通常会提供静态资源的服务以便给用户更好的访问体验,静态文件主要是css,js以及各种图片和字体文件等。

在flask中只需要在项目根目录下创建static目录,在路径中使用/static开头即可。但是为了更好的处理能力,建议使用ngnix或者其他web服务器进行管理。

使用url_for构建路径来访问静态资源,举个例子:

url_for('static',filename='style.css')

生成的路径是“/static/style.css”。

当然了,也可以自定义静态文件的目录

app = Flask(__name__,static_folder='/tmp')

这时访问/static开头的路径时,就是到/tmp目录下寻找资源,而不是默认的static

二、视图

不难发现之前所有的视图都是函数的,简称视图函数。

事实上视图还可以基于类来实现,这样的视图可以支持继承,简称类视图。

但类视图还需要向flask添加路径规则。即app.add_url_rule(url_rule,view_func)进行注册。视图类型有两种。

标准视图

标准视图需要继承flask.views.View,必须实现dispatch_request。

from flask import views
...

class BaseView(views.View):
    def get_template_name(self):
        raise NotImplementedError()

    def render_template(self, context):
        return render_template(self.get_template_name(), **context)

    def dispatch_request(self):
        if request.method != 'GET':
            return ''
        context = {'users': self.get_users()}
        return self.render_template(context)

# 继承父类视图BaseView
class UserView(BaseView):
    def get_template_name(self):
        return 'demo.html'

    @staticmethod
    def get_users():
        return [{
            'username': 'demo',
            'avator': 'this is demo'
        }]

# 注册访问路径
app.add_url_rule('/users', view_func=UserView.as_view('UserView'))

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

当访问/users时,由UserView类执行dispatch_request方法,装配数据,最终返回demo.html页面.

基于调度方法的视图

flask.views.MethodView对每种HTTP方法执行不同的函数,这对RESTful API极其有用。

class UserAPI(views.MethodView):
    def get(self):
        return 'this is get'

    def post(self):
        return 'this is post'

    def delete(self):
        return 'this is delete'


app.add_url_rule('/user', view_func=UserAPI.as_view('userview'))

即请求为get时执行get方法,post时执行post方法。

通过装饰as_view对视图进行装饰,最常用于权限的检查,登录验证。

# 装饰函数
def user_isLogin(f):
    def decorator(*args,**kwargs):
        if not u.user: # 判断用户是否已登录
            abort(401)
        return f(*args,**kwargs)
    return decorator

app.add_url_rule('/user/',view_func=user_isLogin(UserAPI.as_view('user')))

从flask8.0开始还可以在继承MethodView的类中直接修改decorator属性实现相同效果:

class UserAPI(views.MethodView):
    decorator = [user_isLogin] #user_isLogin为函数名

蓝图

蓝图是应用的模块化,使用蓝图可以让应用层次清晰,更易于开发维护项目。

一般用在具有相同url前缀的情况,比如跟用户相关的各种页面/user/center,/user/address,...等都以user开头,那么就可以把它们放在同一个模块中。一个简单的例子如下:

bp_demo.py

from flask import Blueprint

bp = Blueprint('user', __name__, url_prefix='/user')


@bp.route('/')
def bp_demo():
    return '这是bp_demo'

app.py

...
import bp_demo
...

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

那么以/user开头的视图函数就可以写在bp_demo.py中,从而与app.py的视图函数区分开来,用户模块和主页模块分别完成,而不是都写在app.py中。

子域名

说到蓝图就少不了子域名。现在很多网站中都有使用,比如现在一个网站是jh.com,那么可以加一个子域名cms.jh.com作为cms系统的网址,以下例子:

bp_demo.py

from flask import Blueprint

bp = Blueprint('user', __name__, url_prefix='/user',subdomain='cms')


@bp.route('/')
def bp_demo():
    return '这是bp_demo'

app.py  

...
import bp_demo
...
# 配置`SERVER_NAME`
app.config['SERVER_NAME'] = 'jh.com:5000'

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

配置完成后还不能访问,因为host文件中没有相关映射,在主机的host文件中的127.0.0.1 后面增加子域名后即可正常访问。

 

三、模板

终于到这一步了,可以把html页面拿来显示了,不过在这之前再来看python自带的字符串模板:

from string import Template
s = Template("$one : ---- :$two ")
out = s.substitute(one='one的值为1',two='two的值为2')

print(out)

# 输出结果
# one的值为1 : ---- :two的值为2

这里就是通过字符串模板对象的substitute方法把参数插入到对应的变量上,或者说就是在s这个模板字符串上挖了坑,然后往坑里塞东西。

自带的模板功能有限,不能写控制语句,无法继承重用,这样肯定是不够的。所以第三方模板引擎就非常有必要了,目前最知名的就是jiaja2和mako,本次学习以jinja2为主。

jinja2

jinja2是仿django的一个模板引擎,它速度快,使用广泛,并且提供可选的沙箱模板保证环境的安全,与其他诸多web开发一样具有一些优点,如下:

  • 让HTML设计者和后端python开发分离
  • 减少使用python 的复杂度,程序易于维护
  • 模板灵活、快速、安全,对设计者和开发者更友好。
  • 提供了控制语句和模板继承等高级功能,减少开发复杂度。

jinja2的单独使用和string.Template很像:

from jinja2 import Template
t = Template('Hello {{ var }}')
t.render(var='World')
print(t)

# 输出结果
# Hello World

基本语法

模板仅仅是文本文件,通常web开发中使用.html做后缀名。模板包含“变量”或“表达式”,将被替换为值,确定模板中还有表情和控制语句。

一个简单的模板(simple.html)




    
    Title


    {# 这个是jinja的注释,它不会被返回给客户端 #}
    
    
    

{{ title | trim }}

{{ content }}

以上代码的解释:

  • {#...#}:模板注释,在渲染的页面里不会出现。
  • {%...%}:执行语句块,如for,if等等。
  • {{...}}:用于把变量输出到模板上。
  • jiaja中的控制语句,如for循环,需要以endfor作为结束。
  • 在python代码中将变量传递给模板,可以通过点(.)来访问变量的属性,也可以使用括号([]),其效果是一样的
  • 在{{...}}中出现的竖线"|"是过滤器,在这里是将title变量对应字符串的空格去除,jinja2有很多的过滤器,他们大多都很常用。

模板继承

模板继承让模板重用,提高工作效率和代码质量。

先定义一个基础的骨架模板(base.html)




    

    {% block head %}
        {% block title %} {% endblock %}
        
    {% endblock %}


{% block header %}

{% endblock %}
{% block content %}

{% endblock %}
{% block footer %}

{% endblock %}

  • {% block xxx %}...{% endblock%}是一个代码块,可以在子模版重载,其中xxx为该代码块命名
  • head中有默认内容,如果子模板中没有重载,那么该内容也将被字模板使用

然后是子模板index.html

{% extends 'base.html' %}
{% block title %} index {% endblock %}

{% block head %}
    {{ super() }}
    
{% endblock %}

{% block header %}
    

header

{% endblock %} {% block content %}

content

{% endblock content %} {% block footer %}

footer

{% endblock %}

那写一个视图函数来渲染显示看看吧,向模板中传入title变量。

@app.route('/index')
def index():
    title = 'index'
    return render_template('index.html', title=title)

python web之flask学习(三)_第1张图片

可以看到title变量被渲染到标题中。

  • index.html继承了base.html的内容。extentds标签应该在模板一开始使用
  • index.html中调用super(),表示先使用base.html 的head内容,在基于此添加css样式。
  • 在代码块的结束标签中写上名称,可以改善模板的可读性。
  • 如果想要多次使用一个块,可以使用特殊的self变量调用与块同名的函数:

      {% block title %}{% endblock %}

     

{{ self.title() }}

 宏

宏类似函数,把常用行为抽象成可重用的函数。

在index.html中定义宏

python web之flask学习(三)_第2张图片

此后便能类似函数一样使用这个宏

python web之flask学习(三)_第3张图片

赋值

在代码块中也可以为变量赋值,赋值使用set标签,而且可以为多个变量赋值。

在index.html中

python web之flask学习(三)_第4张图片

include、import

include语句用于包含一个模板,渲染时在include语句对应的位置添加被包含的内容:

{% include 'header.html' ignore missing%}
{# ignore missing :如果模板不存在,jinja会忽略这条语句 #}

jinja的import和python类似,可以把整个模板导入到一个变量,或者从其中导入特定的宏。

{% import 'index.html' as index %} {# 导入整个,调用时index.hello #}
{% from 'index.html' import hello as hello%} {# 导入特定宏 #}

你可能感兴趣的:(flask)