Flask 阶段性 问题总结

Flask 阶段性 问题总结注:项目周期太长了,终于有点自己的时间总结下这几个月的项目成果了。还有自己遇到的一些问题跟总结,结合搜集到的知识做个简单的记录吧。-伪造上下文有一种场景特别需要伪造请求上下文 —— 自动测试: @app.route('/genius')def genius(): return 'nothing special'with app.test_reque...
摘要由CSDN通过智能技术生成

Flask 阶段性 问题总结

注:项目周期太长了,终于有点自己的时间总结下这几个月的项目成果了。还有自己遇到的一些问题跟总结,结合搜集到的知识做个简单的记录吧。

-伪造上下文

有一种场景特别需要伪造请求上下文 —— 自动测试:
 
@app.route('/genius')
def genius():
    return 'nothing special'
with app.test_request_context('/genius',method='GET'):
    print app.dispatch_request()

- Jinja2内置全局变量

Jinja2内置的全局对象包括:
 
range([start, ]stop[, step])
lipsum(n=5, html=True, min=20, max=100)
dict(**items)
class cycler(*items)
class joiner(sep=', ')
Flask向Jinja2模板注入了以下全局对象,可以在模板中直接访问:
 
config - 当前Flask应用实例的配置对象
request - 当前HTTP请求对象
session - 当前HTTP请求的会话对象
g - 当前HTTP请求周期内的全局对象
url_for() - URL生成函数
get_flashed_messages() - 闪信函数
下面的示例中,从session中提取当前用户名:
 
@app.route('/')
def v_index():
    tpl = 'welcome back, {{ session.username }}, your user agent is <b>{{ request.headers['User-Agent']}}</b>'
    return render_template_string(tpl)

自定义全局对象

可以使用应用对象的context_processor装饰器向引擎注入额外的全局对象。 下面的示例向模板全局域中注入vendor变量,其值为hubwiz:
 
@app.context_processor
def vendor_processor():
    return dict(vendor='hubwiz')
这时我们可以在模板中直接使用vendor变量了:
 
@app.route('/')
def v_index():
    tpl = 'powered by {{vendor}}'
    return render_template_string(tpl)
当然,同样的方法可以用于注入全局函数。下面的示例向模板全局域中注入format_price 函数:
 
@app.context_processor
def utility_processor():
    def format_price(amount, currency=u'€'):
        return u'{0:.2f}{1}'.format(amount, currency)
    return dict(format_price=format_price)

过滤器与定制过滤器

模板中可以使用过滤器|来修改变量的值。下面的示例使用内置的title过滤器 将name变量中每个单词的首字母转换为大写:
 
tpl = '{{ name|title  }}'
print render_template_string(tpl,name='jimi hendrix') #Jimi Hendrix
过滤器级联 :可以将多个过滤器串联起来,构成过滤流水线。下面的示例对name 变量依次使用了两个过滤器,scriptags过滤器用来除去name变量中的HTML标签, title过滤器将传入的字符串中每个单词的首字母转换为大写:
 
tpl = '{{ name|striptags|title  }}'
print render_template_string(tpl,name='<h1>jimi hendrix</h1>') #Jimi Hendrix
过滤器参数 :可以使用小括号为过滤器传入额外的参数。下面的示例将列表型变量 的多个成员使用join过滤器连接起来:
 
tpl = '{{ seq | join("-") }}'  
print render_template_string(tpl,seq=[1,2,3]) # 1-2-3
在Jinja2中,一个过滤器其实就是一个函数,第一个参数用来接收前序环节传入的值,而 返回值则作为后续环节过滤器函数的第一个参数:
 
Jinja2内置了很多过滤器,在其官网文档页 可以了解详细情况。


过滤器其实就是一个函数。在Flask中,可以使用Flask.template_filter 装饰器创建自己的过滤器。下面的示例创建了一个名为reverse的串反转过滤器,它总是 将输入的字符串逆向重排:
 
@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]
下面的示例演示了如何调用我们自制的过滤器:
 
@app.route('/')
def index():
    return render_template_string('{{ greeting | reverse }}',greeting='Hello, Jinja2' )
另一种等价地创建定制过滤器的方法是将过滤器函数添加到Flask应用实例的jinja_env字典中:
 
def reverse_filter(s):
    return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter

- 递归循环

有些数据是具有不确定层次的递归数据,比如文件系统,目录里还有目录:
 
/application                    ------ 目录          
    /app.py                     ------ 文件
    /static                     ------ 目录
        /main.css               ------ 文件
        /jquery.min.css         ------ 文件
    /templates                  ------ 目录
        /user.html              ------ 文件
其对应的数据表达参见示例中的tree对象。
 
Jinja2的循环结构支持递归调用。使用方法如下:
 
1.使用recursive关键字声明循环为递归循环
 
{% for item in data recursive}
...
{% endfor %}
2.在循环内部,使用loop()函数调用子节点
 
{{ loop(item.children) }}

循环块中的特殊情况与变量

for循环块中,Jinja2提供了关于循环的一些特殊变量:
 
loop.index :当次执行的循环序号,从1开始。下面的示例将输出110{% for i in range(10) %}
{{ loop.index }}
{% endfor %}
loop.index0 :当前执行的循环序号,从0开始。
 
loop.revindex :当前执行的循环反序序号,从1开始。下面的示例将输出101{% for i in range(10) %}
{{ loop.revindex }}
{% endfor %}
loop.revindex0 :当前执行的循环反序序号,从0开始
 
loop.first :如果当次执行是循环中的首次,则值为True。下面的示例将输出TrueFalseFalse....
 
{% for i in range(10) %}
{{ loop.index }}
{% endfor %}
loop.last :如果档次执行时循环中的最后一次,则值为True
 
loop.length :列表中的元素数量
 
loop.cycle(*args) :从一个列表中循环取值。下面的示例将循环输出c1、c2、c3、c1、c2、c3...
 
{% for i in range(10) %}
{{ loop.cycle('c1','c2','c3') }}
{% endfor %}
loop.depth :递归循环的层深,从1开始
 
loop.depth0 :递归循环的层深,从0开始

- 关于变量转义

自动转义 : 在模板中使用autoescape标签可以开启或关闭模板引擎的自动转义 功能。在开启自动转义功能时,
模板引擎将对转义块内的所有变量自动执行转义操作。
 
下面的示例中,使用autoescape标签开启了自动转义:
 
user = {'id':123,'nickname':'< IAMKING>'}
tpl = '''
      {% autoescape true %}
      <h1>homepage of <a href="/user/{{id}}">{{nickname}}</a></h1>
      {% endautoescape %}
      '''
render_template_string(tpl,**user)
但是自动转义开启的时候,会对转义块内所有的变量执行转义操作,即是这些变量压根 不可能包含HTML字符,
或者其内容可控。当变量数量很多时,这将造成不必要的性能损失。
 
我们可以使用safe过滤器将这些可控的变量标记为安全的,渲染引擎将不再对其进行转义。 下面的示例中,使用safe标签取消id变量的转义操作:
 
user = {'id':123,'nickname':'< IAMKING>'}
tpl = '''
      {% autoescape true %}      
      <h1>homepage of <a href="/user/{{id | safe}}">{{nickname}}</a></h1>
      {% endautoescape %}
      '''
render_template_string(tpl,**user)
手动转义 :和自动转义对应的就是手动的对变量执行转义操作。方法是使用escape 过滤器,可以简写为e。
 
下面的示例中,对模板中的nickname变量执行手动转义:
 
user = {'id':123,'nickname':'< IAMKING>'}
tpl = '<h1>homepage of <a href="/user/{{id}}">{{nickname | e }}</a></h1>'
render_template_string(tpl,**user)

- Flask中的一些session细节 :

Session是为Web服务器建立状态的一个成熟模式。会话主要解决两个问题:
 
访问者的标识问题
 
服务器需要识别来自同一访问者的请求。这主要是通过浏览器的cookie实现的。 
访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID。 
这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。
 
Flask框架中,每当一个请求进来时会自动根据请求中cookie的会话ID创建 一个Session类的实例对象。
你可以查看当前请求的cookie验证这一点(会话ID的键 默认为session):
 
@app.route('/')
def v_index():
    return request.cookies['session']
访问者信息的记录问题
 
服务器可以记录、提取指定访问者的历史信息。对每一个会话ID,服务端维护一个 数据上下文,
这个数据运行在内存中,通常在变化时持久化到文件系统中或数据库中。
 
在视图函数内,Flask提供了一个全局对象session,它始终等效于当前请求所对应的 Session类实例对象。
Session类定义了get_item()方法和set_item()方法, 因此我们可以像使用Dict对象一样,
通过[]操作符读取或设置会话变量:
 
@app.route('/')
    if !session['user']:
        return redirect('/login')
    return 'some restricted for authorized users only'
由于默认情况下,Flask将会话对象加密后存储在客户端的cookie里,
因此必须要为应用实例的secret_key属性配置一个加密种子才能使用session:
 
app.secret_key = 'sth. random as a encrypt key.'

###Flask中的数据库###


ORM :对象-关系映射**


ORM的全称是Object Relational Mapping,即对象-关系映射,是面向对象/OO 理念向数据持久化方向的自然延伸,是OO和SQL两股思潮在最高点的自然媾和。
 
还得站在OO拥护者的角度看ORM的诞生。当一切应用都以OO的思想被分解为一个 一个对象以后,设计者突然发现,这些对象只能存活在内存中,插头一拔,什么 都没了。
 
要硬盘!要永生!
 
上世纪90年代OO高潮的时候,恰巧关于数据存储的关系理论也大行其道,硬盘 是关系理论三范式的天下。各种关系数据库产品,做的相当好的一点是其操作 语言基本统一到SQL标准上了,
 
OO界在搞自己的OO数据库未果后,决定联姻关系数据库,实现对象永生的目标。 ORM粉墨登场。
 
ORM的一般性思路
 
ORM的目的是持久化对象,比如你定义一个User类,创建了一堆User对象:
 
class User:
    def __init__(self,id,name,age):
        self.id = id
        self.name = name
        self.age = age
 
user1 = User(1,'Zhang3',20)        
user2 = User(2,'Li4',30)
user3 = User(3,'Wang5',40)
ORM希望你能这样把上面三个对象持久化到硬盘里:
 
user1.save()
user2.save()
user3.save()
然后,第二天上班开机,重新启动程序,可以再把这三个对象找回来:
 
user1 = User.load(id=1)
user2 = User.load(id=2)
user3 = User.load(id=3)
一旦对象找回来,重新进入内存,就是OO的地盘了,无论加加减减都能应付。

关于对象模型的定义

ORM的本质是人为化创造的持久化对象!!!使用ORM是从定义对象模型开始的。
定义一个类User。请注意User类是从db.Model继承 来的:
 
class User(db.Model):
    __tablename__ = 'ezuser'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64),unique=True,index=True)
    age = db.Column(db.Integer)
上面的示例中,你应该注意到了,成员变量被定义为db.Column类的实例:
 
id - id被定义为整型、主键
name - name被定义为字符串类型、建立唯一索引
age - age简单的被定义为整型
User类的成员变量__tablename__定义了这个对象对应的数据表名。这个变量是 可选的,默认情况下,SQLAlchemy将使用类名作为表名。
 
SQLAlchemy支持的常见的字段数据类型如下:
 
db.Integer - 32位整型,对应于Python的int
db.Float - 浮点型,对应于Python的float
db.String - 变长字符串,对应于Python的str
db.DateTime - 日期时间型,对应于Python的datetime.datetime
看到这里,可能你大约明白了。通过这样的定义方法,SQLAlchemy已经搜集到 足够的信息进行数据库操作了:
表名、字段名、字段类型、字段约束(主键信息、 索引信息...
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值