flask之二

预热

  • 在渲染模板的时候,默认会从项目根路径下的templates目录下查找模板
  • 如果想要指定模板路径的时候,就在初始化APP的时候,这样操作即可:
    app = Flask(__name__,template_folder='C:/templates') #template_folder可以指定模板位置

    模板传参

  • 在使用render_template渲染模板的时候,可以传递关键字参数,以后直接在模板中使用就可以了
  • 如果参数过多的话,那么就可以将所有的参数放到一个字典中,然后再传这个参数的时候使用**将字典打散成关键字参数。

    小例子:

  • my_template.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.debug = True
    @app.route('/')
    def hello_world():
    context = {
        'username': 'wanghui',
        'age':19,
        'children':{
            'user':'ccc',
            'type':'stu',
        }
    }
    return render_template('index.html', **context)
    # return render_template('index.html',context=context)
    # return render_template('index.html',username='wanghui',age=19)
    if __name__ == '__main__':
    app.run()
  • templates/index.html
    
    
    
    
    my blog
    
    
    

    这是模板渲染的数据

    {#

    {{ username }}

    #} {#

    {{ age }}

    #} {{ context.username }} {{ context.age }}

    {{ username }}

    {{ children.user }}

    模板中的url_for

    模板中的url_for和视图函数中的url_for是类似的,也是传递视图函数的名字,也可以传递参数。使用的时候,需要在url_for两边加上一个{{ url_for('func_name'),ref='/',id='1'}}

  • templates.py
    from flask import Flask,render_template,url_for
    app = Flask(__name__)
    app.debug = True
    @app.route('/')
    def hello_world():
    return render_template('index.html')
    @app.route('/accounts/login//')
    def login(id):
    return render_template('login.html')
    if __name__ == '__main__':
    app.run(port=8888)
  • templates/index.html
    
    
    
    
    my blog
    
    
    

    这是从模板中渲染的

    登陆

  • templates/login.html
    
    
    
    
    Login page
    
    
    

    这是登录页面

    {#{{ 用来存放变量 }}#} {#{% 用来执行函数或者逻辑代码 %}#}

    过滤器

    有时候我们需要在模板中对一些变量进行处理,那么就必须要类似于python中的函数一样,可以将这个值传到函数中,然后做一些操作。在模板中过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器会根据自己的功能,再返回相应的值,之后再将结果渲染到页面上。

  • 基本语法:{{ variable |过滤器的名字 }}
    guo
  • abs(value):返回一个数值的绝对值。 例如:-1|abs。
  • default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。name|default('xiaotuo')——如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。
  • escape(value)或e:转义字符,会将<、>等符号转义成HTML中的符号。例如:content|escape或content|e。
  • first(value):返回一个序列的第一个元素。names|first。
  • format(value,*arags,**kwargs):格式化字符串。例如以下代码:
    {{ "%s" - "%s"|format('Hello?',"Foo!") }}\
    将输出:Helloo? - Foo!
  • last(value):返回一个序列的最后一个元素。示例:names|last。
  • length(value):返回一个序列或者字典的长度。示例:names|length。
  • join(value,d=u''):将一个序列用d这个参数的值拼接成字符串。
  • safe(value):如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例:
    content_html|safe。
    int(value):将值转换为int类型。
    float(value):将值转换为float类型。
    lower(value):将字符串转换为小写。
    upper(value):将字符串转换为小写。
    replace(value,old,new): 替换将old替换为new的字符串。
    truncate(value,length=255,killwords=False):截取length长度的字符串。
    striptags(value):删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格。
    trim:截取字符串前面和后面的空白字符。
    string(value):将变量转换成字符串。
    wordcount(s):计算一个长字符串中单词的个数。
  • default过滤器详解:
    如果某个变量使用方式是{{ value|default('默认值')}},如果value这个key不存在的话就使用过滤器提供的默认值;如果类似于python中判断一个值是否为False(例如:空字典,空字符串,空列表的话)那么久必须要传递另外一个参数{{ value | default('默认值',boolean=True)}};
    可以使用or来替换default('默认值',boolean=True)(例如{{ siginature or '此人很懒没有留下任何说明'}})
    例子:
  • defaulte_falter.py
    from flask import Flask,render_template
    app = Flask(__name__)
    @app.route('/')
    def index():
    context = {
        'position':-9,
        'signature':'',
        #'signature':'this ismy blog'
    }
    return render_template('index.html',**context)
    if __name__ == '__main__':
    app.run(debug=True)
  • templates/index.html
    
    
    
    
    MyBlog
    
    
    {#

    个性签名:{{ signature|default('此人很懒没有留下任何说明!',boolean=True) }}

    #}

    个性签名:{{ signature or '此人很懒没有留下任何说明!'}}

  • esacape:转义过滤器
    • safe过滤器:可以关闭一公分字符串的自动转义
    • escape过滤器:对某个字符串进行转义
    • autoescape过滤器:可以对其代码框内的代码块关闭自动转义
    • first:返回序列中的第一个元素
  • last:返回序列中的最后一个元素
  • format:格式化输出
  • length:长度计算
  • int:转换成整数
  • replase:旧字符串换成新的
  • truncate:指定长度截取(结合striptags去除掉html字段之后截取纯净字符串然后按字数去做预览页填充)
  • striptags:去除标签中的html字段
  • worldcount(s):统计一个长字符串中的单词数
    小例子:
  • escape.py
    from flask import Flask,render_template
    app = Flask(__name__)
    @app.route('/')
    def hello_world():
    context = {
        'position':-9,
        'signature':'',
        'persons':['abc','def'],
        'age':"18",
        'article':'hello hello xxooo xxooo!!'
    }
    return render_template('index.html',**context)
    if __name__ == '__main__':
    app.run(debug=True,port=8080)
  • templates/index.html
    
    
    
    
    MyBlog
    
    
    {#{% autoescape off %}#}
    {#

    个性签名:{{ signature }}

    #} {#{% endautoescape %}#}

    {{ signature|safe }}

    {{ persons|first }}

    {{ persons[0] }}

    {{ persons|last }}

    {{ persons[-1] }}

    {{ "我的名字是%s"|format("hello word!") }}

    {{ "人数是 %d"|format(persons|length) }}

    {% if age|int == 18 %}

    年龄是18岁

    {% else %}

    年龄不是18岁

    {% endif %}

    {{ article|replace('hello','sssssz') }}

    {{ article|truncate(length=5) }}

    {{ signature|striptags }}

    自定义模板过滤器

    1. 在python文件中写好自己的过滤器(本质上就是一个函数)
    2. 如果要在模板中调用这个过滤器,那就需要在这个函数上加一个装饰器@app.template_filter('过滤器名称')
    3. 自动加载的话就在app下添加
      app.config['TEMPLATES_AUTO_RELOAD'] = True
  • 小例子:
  • define_filter.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    @app.route('/')
    def hello_world():
    context={
        'article':'anyway hello anyway hello abccc'
    }
    return render_template('index.html',**context)
    @app.template_filter('cut')
    def cut(value):
    vaule = value.replace("hello","sbsb")
    return value
    if __name__ == '__main__':
    app.run(debug=True,port=9090)**
  • templates/index.html
    
    
    
    
    myblog
    
    
    

    {{ article|cut }}

    实战自定义过滤器

  • 时间处理(从现在到发帖的时间差)
  • shizhan.py
    from flask import Flask,render_template
    from datetime import datetime
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    @app.route('/')
    def index():
    context={
        'article':'aaa bbb ccc',
        'create_time':datetime(2018,02,23,10,12,11)
    }
    return render_template('index.html',**context)
    @app.template_filter('handle_time')
    def handle_time(time):
    '''
    1.距离现在的时间多久,如果间隔在一分钟以内就表示刚刚
    2.在一小时以内就显示xx分钟前
    3.在24小时以内就显示xx小时前
    4. 在一个月之内就显示多少天之前
    5. 否则就显示具体的时间
    :param time:
    :return:
    '''
    if isinstance(time,datetime):
        now = datetime.now()
        timestamp = (now - time).total_seconds() #获取间隔秒数
        if timestamp < 60:
            return "刚刚"
        elif timestamp >=60 and timestamp<= 60*60:
            minutes = timestamp/60
            return "%s分钟前",int(minutes)
        elif timestamp >= 60*60 and timestamp <= 60*60*24:
            hours = timestamp/(60*60)
            return "%s小时前",int(hours)
        elif timestamp >= 60*60*24 and timestamp<= 60*60*24*30:
            days = timestamp/(60*60*24)
            return "%s天前",int(days)
    else:
        return time.strftime('%Y-%m-%d %H:%M')
    if __name__ == '__main__':
    app.run(port=9092,debug=True)
  • templates/index.html
    
    
    
    
    MyBlog
    
    
    

    发表时间:{{ create_time|handle_time }}

    条件判断

    For循环

    jinjia2中的for循环,跟python中的for循环基本是一致的,也是用for in形式;
    而且可以便利所有的序列以及迭代器,但是唯一不同的是jinjia2中的for循环没有breakcontinue

  • 小例子:
  • for_ex.py
    from flask import Flask,render_template
    app = Flask(__name__)
    @app.route('/')
    def hello_world():
    context = {
        'users':['user01','user02','user03'],
        'person':{
            'username':'wanghui',
            'age':21,
            'country':'china',
        },
        'books':[
            {
                'name':'sk1',
                'author':'saa',
                'price':100,
            },
            {
                'name': 'aaaeede1',
                'author': 'se232aa',
                'price': 103,
            },
            {
                'name': 'AAAew',
                'author': 'VVVeqwea',
                'price': 190,
            },
            {
                'name': 'skfdfds1',
                'author': 'sdfsfsdfdaa',
                'price': 30,
            }
        ]
    }
    return render_template('index.html',**context)
    if __name__ == '__main__':
    app.run(debug=True)
  • templates/index.html
    
    
    
    
    MyBlog
    
    
    
      {% for user in users %}

      {{ user }}

      {% endfor %}
    {% for key,value in person.items() %} {% endfor %}
    用户名 年龄 国家
    {{ value }}
    {% for book in books %} {% if loop.first %} {% elif loop.last %} {% else %} {% endif %} {% endfor %}
    ID 书名 作者 价格 总数
    {{ loop.index }} {{ book.name }} {{ book.author }} {{ book.price }} {{ loop.length }}
    {% for x in range(1,10) %} {% for y in range(1,x+1) if y <= x %} {% endfor %} {% endfor %}
    {{ y }}*{{ x }}={{ x*y }}

    模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值
    使用宏的时候,参数可以是默认值

  • 小例子:
  • macro.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    app.config['DEBUG'] = True
    @app.route('/')
    def hello_world():
    return render_template('index.html')
    if __name__ == '__main__':
    app.run(port=9999)
  • templates/index.html
    
    
    
    
    Macro
    
    
    {% macro input(name="",value="",type="text") %}
        
    {% endmacro %}
    

    登陆页面

    用户名: {{ input('username') }}
    密码: {{ input('password',type='password') }}
    {{ input(value='提交',type='submit') }}

    宏的导入

    在真实的开发中,会将一些常用的宏单独放在一个文件中,在需要使用的时候,再从这个文件中进行导入。
    import语句的用法跟python中的import类似,可以直接import...as...,也可以from...import...或者from...import...as...,假设现在有一个文件,叫做forms.html,里面有两个宏分别为input和textarea,如下:

注意事项:
a. inport宏文件 as xxx
b. from 宏文件路径 import 宏的名字 [as xxx]
c. 宏文件的路径,不要以相对路径去找,都要以templates作为绝对路径去找
d. 如果想要在导入宏的时候,就把当前末班的一些参数传递给宏所在的模板,那么就应该在导入的时候使用
with context

  • 小例子:
  • macros.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    app.config['DEBUG'] = True
    @app.route('/')
    def hello_world():
    return render_template('index/index.html')
    if __name__ == '__main__':
    app.run(port=9999)
  • templates/macros/macros.html
    {% macro input(name="",value="",type="text") %}
    
    {% endmacro %}
  • templates/index/index.html
    {#{% from "macros.html" import input as inp %}#}
    {% import "macros/macros.html" as macros with context %}
    
    
    
    
    Macro
    
    
    

    登陆页面

    用户名: {{ macros.input('username') }}
    密码: {{ macros.input('password',type='password') }}
    {{ macros.input(value='提交',type='submit') }}

    include标签

    1. 这个标签相当于是将指定模板中的代码复制粘贴到当前的位置
    2. include标签,如果要继续使用父模板中的变量,直接用就可以了
    3. include的路径也和import一样,需要从templates为根,不要以相对路径去找。
  • 小例子:
  • include_ex.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config['TEMPLATES_AUTO_RELOAD']
    @app.route('/')
    def hello_world():
    return render_template('index.html',username='wanghui')
    @app.route('/detail/')
    def detail():
    return render_template('course_detail.html')
    if __name__ == '__main__':
    app.run(debug=True)
  • templates/index.html
    
    
    
    
    MyBlog
    
    
    {% include "common/header.html" %}
    
    中间的
    {% include "common/footer.html" %}
      {{ username }}
  • templates/course_detail.html
    
    
    
    
    Title
    
    
    {% include "common/header.html" %}
    
    文章详情!
    {% include "common/footer.html" %}
  • templates/common/header.html
    
    
  • templates/common/footer.html
    这是底部

set with语句

  • 在模板中,可以使用set来定义变量;一旦定义了这个变量。那么在后面的代码中,都可以使用这个变量。
  • with语句定义的变量,只能在with的代码块中使用。超出with代码块,则不能使用
  • with不一定要跟一个变量,也可以是一个空的with语句,以后要用的话,就在with中使用set定义的变量来使用。

{% set username='wanghui' %}

用户名:{{ username }}

{% with %} {% set cla***oom='2018' %}

班级:{{ cla***oom }}

{% endwith %}

别的班级{{ cla***oom }}

加载静态文件

  • 加载静态文件使用的是url_for函数,第一个参数为static,第二个参数是filename='path'
  • 路径查找要以static目录作为根目录
  • 小例子:
    • static_ex.py
      from flask import Flask,render_template
      app = Flask(__name__)
      app.config.update({
      'DEBUG':True,
      'TEMPLATES_AUTO_RELOAD':True,
      })
      @app.route('/')
      def hello_world():
      return render_template('index.html')
      if __name__ == '__main__':
      app.run()
  • static/css/index.css
    body{
    background: pink;
    }
  • static/js/index.js
    alert('hello user!')
  • static/imgs/sas.jpg
    图片
  • templates/index.html
    
    
    
    
    Title
    
    
    
    
    
    
    

    模板继承

    为什么需要模板继承?

  • 可以将一些公用的代码单独抽取出来放到一个父模板中,以后子模板直接继承就给可以使用了。
  • 这样可以减少重复性的代码,并且以后代码修改起来也很方便

    模板继承的语法

  • 使用extends语句来指明继承的父模板。父模板的路径也就是相对于templates文件夹下的绝对路径。例子如下{% extends 'base.html' %}

block语法

一般在父模板中只能定义一些共性公用的代码,子模板可能要根据不同的需求实现不同的代码。这时候父模板就应该提供一个接口,让子模板来实现。从而实现业务的具体功能。

  • 在父模板中
    {% block body_block %}
    

    我是base下的

    {% endblock %}
  • 在子模板中
    {% block body_block %}
    

    我是index的内容

    {% endblock %}

    调用父模板代码block中的代码

    默认情况下,字幕版实现了父模板定义的block,那么子模板中block的代码就会覆盖掉父模板中的代码,要想保留父模板中的block的话就是用{{ super() }}来实现

  • 父模板的内容:
    {% block body_block %}
    

    base.html

    {% endblock %}
  • 子模板中的内容:
    {% extends 'base.html' %}
    {% block body_block %}
    {{ super() }}
    

    我是index的内容

    {% endblock %}

    调用另外一个block中的代码

    在另外一个模板中使用其他模板中的代码,可以使用{{ self.blockname() }}即可

  • 父模板
    {% block title %}
    {% endblock %}
    
    {% block body_block %}
    

    base.html

    {% endblock %}
  • 子模板:
    {% extends 'base.html' %}
    {% block title %}
    MyIndex
    {% endblock %}
    {% block body_block %}
    {{ super() }}
    {{ self.title() }}
    

    我是index的内容

    {% endblock %}

    其他注意事项

  • 继承的代码必须放在子模板中的第一行{% extends 'base.html' %}
  • 子模板中要实现自己的代码,要放到block中,不然不生效

    继承的例子:

  • inherit_ex.py
    from flask import Flask,render_template
    app = Flask(__name__)
    app.config.update({
    'DEBUG':True,
    'TEMPLATES_AUTO_RELOAD':True
    })
    @app.route('/')
    def index():
    return render_template('index.html')
    @app.route('/detail/')
    def detail():
    return render_template('course_detail.html')
    if __name__ == '__main__':
    app.run()
  • templates/base.html
    
    
    
    
    {% block title %}
    {% endblock %}
    
    
    
    
    {% block body_block %}
    

    base.html

    {% endblock %}
    这是底部
  • templates/index.html
    {% extends 'base.html' %}
    {% block title %}
    MyIndex
    {% endblock %}
    {% block body_block %}
    {{ super() }}
    {{ self.title() }}
    

    我是index的内容

    {% endblock %}
  • templates/course_detail.html
    {% extends 'base.html' %}
    {% block body_block %}
    

    this is course

    {% endblock %}