docker
不同于ports
, link
, docker-compose的command如果不使用多条语句 , 不能使用列表
flask
Model
flask的model在设计的时候 , 应该尽可能保证数据表的PK无意义化 , 不要使用实体的唯一属性作为PK , 力求让主键的唯一作用就是唯一标识
在编写Model的时候 , 需要在文档注释说明每个字段及其含义
flask的自增列不能自己添入,必须交给sql自己自增填入
就算是远程数据库 , flask不能自己手动使用sql创建表,必须使用create_all()函数创建.操作同样会响应到远程数据库 . 而且注意 , create_all()并不能创建数据库 , 必须手动创建数据库才能使用create_all()
Sqlalchemy的remote_side : 表中的外键引用的是自身时,如Node类,如果想表示多对一的关系,那么就可以使用remote_side
form
- 使用form时 , 不要手写submit标签 , 直接使用SubmitField字段即可 :
submit = SubmitField('登录')
template
macro使用
**kwargs
参数和*args
参数 , 不需要在函数括号()里声明 , 直接在函数里调用**kwargs
和*args
即可1
2
3
4
5
6
7
8
9
10
11
12
13{% macro render_field(field) %}
{% with errors = field.errors %}
<div class="form-group{{ 'has-error' if errors }}">
{{ field.label(class="control-label") }}
{{ field(class='form-control', **kwargs) }}
{% if errors %}
{% for error in errors %}
<span class="help-block" style="color: red">{{ error }}</span>
{% endfor %}
{% endif %}
</div>
{% endwith %}
{% endmacro %}对于不敏感的用户配置 , 如navi的收缩状态 , 可以使用LocalStorage储存
view
切换redis的时候报UnicodeDecodeError 错误 , 有可能是redis中存在相关持久化文件,记住了前面的任务和配置信息,使得redis在进行get和set的时候出现混乱,造成错误 . 此时只要重启即可 .
Flask使用redis作为缓存装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22def cache_table_data(cache_time=60):
def decorator(func):
def warpper(cls, *args, **kwargs):
""" redis 缓存装饰器 """
args_key = ".".join([str(k) for k in args])
redis_key = "table:{}:{}:{}-{}".format(
cls.__name__,
func.__name__,
args_key,
json.dumps(kwargs)
)
# 获取缓存
cache_data = cache_client.get(redis_key)
if cache_data:
data = pickle.loads(cache_data)
else:
data = func(cls, *args, **kwargs)
cache_data = pickle.dumps(data)
cache_client.set(redis_key, cache_data, cache_time)
return data
return warpper
return decorator生成签名的方式
1
2
3
4
5
6
7def generate_signature(req):
'''生成签名'''
req_str = '&'.join(['{}={}'.format(k, v) for k, v in sorted(req.items())])
secret_key = current_app.config['ZK_LOGIN_SECRET_KEY']
unsign_str = req_str + secret_key
sign = md5(unsign_str.encode()).hexdigest()
return sign
other
flask里时间字段的管理 , 可以编辑一个命名元组 , Nametuple的属性就是各个时间的表示
1
2
3
4
5
6
7
8
9import datetime
from collections import namedtuple
_Time = namedtuple("Time", ("timestamp", "date", "datetime"))
def get_all_time():
now = datetime.datetime.now()
timestamp = int(now.strftime("%s"))
return _Time(timestamp=timestamp, date=now.date(), datetime=now)使用redis的setex可以实现分布式锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29class RedisLock:
"""redis dist lock
@param name 锁名称
@param client redis连接
@param timeout 超过多少ms锁不释放,则自动过期
@param retries 重试次数
"""
def __init__(self, name, client, timeout=2000, retries=0):
assert retries >= 0, 'retries must >= 0'
self.key = "distributed-redis-lock:%s" % name
self.client = client
self.timeout = timeout
self.retries = retries
self.has_lock = False
def __enter__(self):
while True:
is_ok = self.client.set(self.key, 1, ex=self.timeout, nx=True)
if is_ok:
self.has_lock = True
return self
if self.retries == 0:
break
self.retries -= 1
time.sleep(0.1)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.client.delete(self.key)Flask-login内部逻辑
每次访问被保护的视图(调用login_required时)都会新形成一个current_user对象 , 该对象从请求上下文栈顶获取user属性
新形成current_user的时候都会调用_loader_user()方法 , 该方法会去上下文中寻找user属性
在获取失败的时候调用
_loader_user
方法 , 该方法会调用_load_user , 继而调用reloader_user方法 , reloader_user方法就能生成新的user对象,并且将相关信息写入session
api文档的内容 : 接口功能 , 接口地址 , 接口所需参数(必须参数 , 非必须参数 , 通用参数) , 接口返回数据 , 数据字段 , 状态码 ,错误码
python修改环境变量 : 若没有特别设定,环境变量继承自父进程。因此,你在 python 里面修改了环境变量,只能影响自身,及由它创建的子进程(若没有显式设定)。
代码复用的方法 : 装饰器 , 钩子函数 , 封装函数 , 创建父类