docker

不同于ports , link , docker-compose的command如果不使用多条语句 , 不能使用列表

flask

Model

  1. flask的model在设计的时候 , 应该尽可能保证数据表的PK无意义化 , 不要使用实体的唯一属性作为PK , 力求让主键的唯一作用就是唯一标识

  2. 在编写Model的时候 , 需要在文档注释说明每个字段及其含义

  3. flask的自增列不能自己添入,必须交给sql自己自增填入

  4. 就算是远程数据库 , flask不能自己手动使用sql创建表,必须使用create_all()函数创建.操作同样会响应到远程数据库 . 而且注意 , create_all()并不能创建数据库 , 必须手动创建数据库才能使用create_all()

  5. Sqlalchemy的remote_side : 表中的外键引用的是自身时,如Node类,如果想表示多对一的关系,那么就可以使用remote_side

form

  1. 使用form时 , 不要手写submit标签 , 直接使用SubmitField字段即可 : submit = SubmitField('登录')

template

  1. 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 %}
  2. 对于不敏感的用户配置 , 如navi的收缩状态 , 可以使用LocalStorage储存

view

  1. 切换redis的时候报UnicodeDecodeError 错误 , 有可能是redis中存在相关持久化文件,记住了前面的任务和配置信息,使得redis在进行get和set的时候出现混乱,造成错误 . 此时只要重启即可 .

  2. Flask使用redis作为缓存装饰器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    def 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
  3. 生成签名的方式

    1
    2
    3
    4
    5
    6
    7
    def 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

  1. flask里时间字段的管理 , 可以编辑一个命名元组 , Nametuple的属性就是各个时间的表示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import 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)
  2. 使用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
    29
    class 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)
  3. Flask-login内部逻辑

    1. 每次访问被保护的视图(调用login_required时)都会新形成一个current_user对象 , 该对象从请求上下文栈顶获取user属性

    2. 新形成current_user的时候都会调用_loader_user()方法 , 该方法会去上下文中寻找user属性

      在获取失败的时候调用_loader_user方法 , 该方法会调用_load_user , 继而调用reloader_user方法 , reloader_user方法就能生成新的user对象,并且将相关信息写入session

  4. api文档的内容 : 接口功能 , 接口地址 , 接口所需参数(必须参数 , 非必须参数 , 通用参数) , 接口返回数据 , 数据字段 , 状态码 ,错误码

  5. python修改环境变量 : 若没有特别设定,环境变量继承自父进程。因此,你在 python 里面修改了环境变量,只能影响自身,及由它创建的子进程(若没有显式设定)。

  6. 代码复用的方法 : 装饰器 , 钩子函数 , 封装函数 , 创建父类