最近在将本站升级为python语言,并使用flask进行实现,中途遇见的问题和一些方法的记录
token及密码校验
class user_info(db.Model):
__tablename__ = 'user_info'
username = db.Column(db.Integer, primary_key=True)
password = db.Column(db.String(255), unique=False)
role = db.Column(db.Integer, unique=False)
name = db.Column(db.String(255), unique=False)
def to_dict(self):
'''将对象转换为字典数据'''
reDict = {
"username": self.username,
"role": self.role,
"name": self.name,
}
return reDict
# 获取token,时长秒
def generate_auth_token(self, expiration=3600 * 24):
s = Serializer(app.config['SECRET_KEY'], expires_in=expiration)
return s.dumps(self.username)
# 通过token解析用户信息
@staticmethod
def verify_auth_token(token):
s = Serializer(app.config['SECRET_KEY'])
try:
username = s.loads(token)
except SignatureExpired:
print('SignatureExpired', SignatureExpired)
return None # valid token, but expired
except BadSignature:
print('BadSignature', BadSignature)
return None # invalid token
except Exception as e:
print('Error: ', e)
return None
user = heanny_user_info.query.get(username)
return user
def hash_password(self, password): # 加密
self.password = pwd_context.encrypt(password)
def verify_password(self, password): # 解密
return pwd_context.verify(password, self.password)
model外键
class h_posts(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255), unique=False)
content = db.Column(db.Text, unique=False)
user = db.Column(db.String(255),db.ForeignKey(user_info.username), unique=False)
author = db.relationship('user_info', backref=db.backref('h_posts'))
分页
pagination = posts.query.order_by(desc('id')).paginate(page=int(page) if page else 1, per_page=15, error_out=False)
blogs = list(map(lambda x: x.to_dict(), pagination.items))
blog.html
<ul class="pagination flex-wrap">
{% if pagination.has_prev %}
<li class="page-item">
<a href="blog-1.html" class="page-link" data-ci-pagination-page="1"
rel="start"><i class="fa fa-angle-double-left"></i></a>
</li>
<li class="page-item ">
<a href="/blog-{{ pagination.prev_num }}.html" class="page-link"
data-ci-pagination-page="{{ pagination.prev_num }}" rel="prev">
<i class="fa fa-chevron-left"></i></a>
</li>
{% endif %}
{% for page in pagination.iter_pages(0,2,4,1) %}
{% if page %}
<li class="page-item {% if page==pagination.page %}active{% endif %}">
<a class="page-link" href="/blog-{{ page }}.html">{{ page }}</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">…</a></li>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<li class="page-item ">
<a href="/blog-{{ pagination.next_num }}.html" class="page-link"
data-ci-pagination-page="{{ pagination.next_num }}" rel="next"><i
class="fa fa-chevron-right"></i></a>
</li>
<li class="page-item ">
<a href="/blog-{{ pagination.pages }}.html" class="page-link"
data-ci-pagination-page="pagination.pages"><i class="fa fa-angle-double-right"></i></a>
</li>
{% endif %}
</ul>
模板渲染
Jinja2模版:
- 让页面逻辑独立于业务逻辑,开发的程序易于维护
- 提供流程控制,继承等高级功能使得模版非常灵活,快速,安全
强大模版
模版支持任何基于文本的格式(HTML/XML/CSV/LaTex等等),并没有特定的扩展名
基础语法:
{%- ... -%} 说明: 主要解析流程控制等 {#- ... -#} 说明: 主要添加代码注释等 {{ ... }} 说明: 主要解析模版表达式
数据类型
说明: 模版中支持字符串,数值,列表,元组,字典, boolean(true/false,注意是小写的),除此之外还支持全局函数/内置过滤器|/内置测试器is/in关键字/if关键字/字符连接符~
- 支持算术运算符,+,-,/,//,%,,*,
- 支持比较运算符,==,!=,>,>=,<,<=
- 支持逻辑运算符,and,or,not,(expr)
- 支持其它运算符,in,is,|,~(连接字符串使用{{ ‘hello ‘ ~ name ~ ‘!’ }},如果name是limanman则返回hello limanman!),()调用可调用量,./[]获取对象属性
变量相关
应用可将任意类型变量传递给模版,访问带属性变量既可以加.访问,也支持[]访问,两者的区别是查找的先后顺序,前者先加.测试,然后再[]测试,后者先[]测试然后在.测试,所以根据具体传递变量类型决定
模版中中可以为变量赋值,在顶层的(块,宏,循环之外)赋值是可导出的,也就是说可以从别的模块儿中导入使用
{%- set navigation = [('index.html', 'Index'), ('about.html', 'About')] -%} {%- set key, value = call_something() -%}
with语句
- 模版中支持with语句,和PY内置with类似,with后面常跟表达式,主要用于限制对象的作用域
% with arr=range(10) %} {% for i in arr %} {{ i }} {% endfor %} {% endwith %}
过滤器
- 过滤器和管道符|配合可链式修改变量,过滤器还支持传递参数,内置的过滤器列表可参考(http://docs.jinkan.org/docs/jinja2/templates.html#builtin-filters)
{{ v|abs }} 说明: 返回值的绝对值 {{ v|attr(name) }} 说明: 返回v对象的name属性值 {{ v|batch(linecount, fill_with=None) }} 说明: 将v序列linecount个元素分为一组,保证每组长度相同,如果不够用fill_with的值补充,常用于生成表格
<!--说明: 创建一个10行10列的表格,通过batch分割成10行,然后再次遍历生成10个td--> <table width="600px" style="border-collapse: collapse;margin: 0 auto;" border="1"> {%- for tr in table_tds|batch(10, " ") -%} <tr> {%- for td in tr -%} <td>{{ td }}</td> {%- endfor -%} </tr> {%- endfor -%} </table>
{{ v|capitalize }} 说明: 整个语句的首字母大写,其它字母小写 {{ v|default(default_value='', boolean=False) }} 说明: boolean为False,只有未定义时才返回default_value,boolean为True时,只要v为False就使用default_value. {{ v|dictsort(case_sensitive=False, by='key') }} 说明: 对v字典进行排序case_sensitive设置是否大小写敏感,by指定键排序 {{ v|escape }} 说明: 对v进行安全转义,可以简写为e {{ v|filesizeformat(binary=False) }} 说明: 格式化v为可读的文件大小默认以字节为单位 {{ v|first }} 说明: 返回序列对象的第一个元素 {{ v|float(default=0.0) }} 说明:转换value值为float类型,如果转换失败则返回default的值 {{ v|forceescape }} 说明: 不管v是否被转义过,一律进行html转义,可能会二次转义 {{ v|format(*args, **kwargs) }} 说明: 使用*args和**kwargs去填充格式化字符串v {{ v|groupby(attr) }} 说明: 对序列v中的对象/字典按照attr分组,分组后组名存储在group.grouper里,而组员保存在group.list,如下是一个站点地图的简单实现
<ul> {%- for group in persons|groupby("gender") -%} <li>{{ group.grouper }}</li> <ul> {%- for person in group.list -%} <li>{{ person['name'] }}, {{ person['age'] }}</li> {%- endfor -%} </ul> {%- endfor -%} </ul>
{{ vint(default=0) }} 说明: 将v的值转换为int如果转换失败返回default的值 {{ v|join(d='', attribute=None) }} 说明: 使用d分割符拼接v,如果attribute为字符串则首先获取value的attribute属性然后用d分割符去拼接属性值 {{ v|last }} 说明: 返回序列对象v的最后一个元素 {{ v|length }} 说明: 说明返回对象的长度 {{ v|list }} 说明: 转换v为列表,如果value为字符串则转换为字符列表 {{ v|lower }} 说明: 转换为小写 {{ v|map(filter/attribute='') }} 说明: filter过滤器作用域v的每个元素,attribute过滤出v中包含指定属性的元素
{%- for val_unit in [1024, 2048, 4096]|map('filesizeformat') -%} <p>{{ val_unit }}</p> {%- endfor -%}
{{ v|pprint(verbose=False) }} 说明: 更优美的方式打印,用于调试 {{ v|random }} 说明: 从序列对象中随机返回一个元素 {{ v|replace(old, new, count=None) }} 说明: 将v中的old替换为new,如果指定了count定义替换n次 {{ v|reverse }} 说明: 反转value序列 {{ v|round(precision=0, method='common') }} 说明: 四舍五入v的值precision表示保留小数点几位,method的值可以为common/ceil/floor {{ v|safe }} 说明: 标记value为安全字符串,按照正常规则去解析 {{ value|sort(reverse=False, case_sensitive=False, attribute=None) }} 说明: 如果指定attribute则按照attribute排序,reverse表示是否逆向排序,case_sensitive表示是否区分大小写
{%- for cur_item in data|sort(false, true, attribute='index') -%} <p>{{ cur_item['index'] }}</p> {%- endfor -%}
{{ v|string }} 说明: 将v对象转换为字符串 {{ v|striptags }} 说明: 清除v中的html/xml等文档中的标签 {{ v|sum(attribute=None, start=0) }} 说明: 如果设置了attribute则会获取v中所有元素的attribute属性的值的总和,start为初始值 {{ v|title }} 说明: 让v中的每个字母的首字母大写 {{ v|trim }} 说明: 去除v两边的空白 {{ v|truncate(length=255, kilwords=False, end='...') }} 说明: v字符串超过length长度的部分用...代替,如果要精确到字符的话需设置killwards为true,否则设置为false {{ v|tojson|safe }} 说明: 将v转换为json,但是为了不被转义,常常配合safe在JavaScript脚本中使用
```html<script type="text/javascript"> var users = {{ users|tojson|safe }} for(var i=0; i<users.length; i++){ console.log(users[i].name) } </script>
{{ v|upper }}
说明: 把v中的所有字符转换为大写
{{ v|urlencode }}
说明: 将v进行URL编码
{{ v|urlize(trim_url_limit=None, nofollow=False) }}
说明: 转换v为可点击的url连接地址,trim_url_limit设置url显示的长度,超出长度用…填充
{{ v|wordcount }}
说明: 获取s中的单词的数量 - 除了内置过滤器还支持自定义过滤器,非常简单可通过app.add_template_filter(func, name)函数或@@app.template_filter(name)修饰器来自定义过滤器,两种方法内部调用的都是app.jinja_env.filters[name] = func实现的,但并不推荐直接设置jinja2环境,所以还是推荐前两种方法
```html```python @monitor.app_template_filter('sub') def sub_filter(inputs, start, end, step): return inputs[startstep]
全局函数
- 如果说过滤器是一个变量转换函数,测试器是一个变了测试函数,那么全局函数就可以是任何函数,可以在任一场景使用,没有输入和输出值限制,全局函数可参考,http://docs.jinkan.org/docs/jinja2/templates.html#builtin-globals
range([start], stop[, step])
说明: 返回一个包含整等差级数的列表
dict(**items)
说明: 方便的字典替代品{‘foo’: ‘bar’}等价于dict(foo=bar)
lipsum(n=5, html=True, min=20, max=100)
说明: 在模版中生成lipsum乱数假文,默认会生成5段html,每段20到100词之间,如果html被禁用,则会返回常规文本,在测试布局时生成简单内容时很有用
joiner(sep)
说明: 初始化一个分割符,第一次调用返回空字符,以后调用返回分割符,常用于分割循环中的内容```html <ul> {%- set sep = joiner('|') -%} {%- for title in ['资产管理', '主机分组', '主机信息'] -%} {%- set s = '<i>' ~ sep() ~ '</i>' if sep() -%} {{ s|safe }} <li><a href="#">{{ title }}</a></li> {% endfor %} </ul>
说明: 在模版中生成乱数假文,默认会生成5段html,每段在20到100词之间,如果HTML被禁用,会返回常规文本,在测试布局时生成简单内容很有用 cycler(*items) 说明: 周期性的从若干个值的循环,周期实例.next()返回当前项并跳到下一个,.reset()重置周期计到第一个项,.current返回当前项
{%- set cur_datas = range(1, 101, 1) -%} {%- set row_class = cycler('light', 'dark') -%} <table style="margin: 0 auto;border-collapse: collapse" width="600px" border="1"> {%- for tr in cur_datas|slice(10) -%} <tr class="{{ row_class.next() }}"> {%- for td in tr -%} <td>{{ td }}</td> {%- endfor -%} </tr> {%- endfor -%} </table>
join(sep=',') 说明: 连接多个项
```html{{ range(10)|join(',') }}
- 除了内置全局函数还支持自定义全局函数,非常简单,通过app.add_template_global(func, name)函数或@app.template_global(name)修饰器来自定义全局函数,两种方法内部调用的都是app.jinja_env.globals[name] = func实现的,但并不推荐直接设置jinja2环境,所以还是推荐前两种方法
```python @monitor.app_template_global('endswith') def ends_width(s, suffix): return s.endswith(suffix)
# 转义相关 1.单行可用{{ '{{}}' }}作为原始字符串实现转义,多行可使用raw(如展示Jinja2语法的实例)
<li>{{ '{{' }}</li> {% raw %} {% for item in seq %} <li>{{ item }}</li> {% endfor %} {% endraw %}
模版继承
- Jinja2最强大的部分就是模版继承,模版继承允许你构建一个包含你站点公共元素的基本模版’骨架’,并定义子模版可以覆盖的块
<!DOCTYPE html> <html {% block html_attribs %}{%- endblock -%}> {%- block html -%} <head> {%- block head -%} {% block meta %} {%- endblock -%} {% block styles %} {%- endblock -%} {%- endblock -%} </head> <body {%- block body_attribs -%}{%- endblock -%}> {%- block body -%} {%- block scripts -%} {%- endblock -%} {%- endblock -%} </body> {%- endblock -%} </html>
{%- extends 'base.html' -%} {%- block head -%} {{ super() }} {#- 头部区 -#} {%- endblock -%} {%- block body -%} {{ super() }} {#- 主体区 -#} {%- endblock -%} {%- block styles -%} {{ super() }} {#- 样式区 -#} {%- endblock -%} {%- block scripts -%} {{ super() }} {#- 脚本区 -#} {%- endblock -%}
暂无评论,还不快来坐沙发...