Please enable Javascript to view the contents

开发 Tips(2)

 ·  ☕ 3 分钟

主要记录最近遇到的一些开发问题,解决方法。

1. Python 中的序列化与反序列化

序列化,将内存对象转化为可存储或传输序列的过程。反序列化,把序列化序列重新转化为内存对象的过程。Json 和 Pickle 是 Python 中常用的两个序列化处理模块。

Json VS Pickle:

  • Json 实现的是内存对象与 Json 字符串的转换,Pickle 实现的是内存对象与字节对象的转换
  • Json 格式广泛应用于除 Python 外的其他领域,Pickle 是 Python 独有的
  • Json 只能序列化 Python 内置的基本数据类型对象,Pickle 可以序列化一切对象,包括函数
  • cPickle 是 Pickle 的 C 语言实现,常用来替换 Pickle 以提升性能

使用示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# -*- coding: utf-8 -*-
import json
import pickle


obj = {'a': 'b', 'c': 'd'}
ps = pickle.dumps(obj)
print ps
# "(dp0\nS'a'\np1\nS'b'\np2\nsS'c'\np3\nS'd'\np4\ns."
js = json.dumps(obj)
print js
# {"a": "b", "c": "d"}
print pickle.loads(ps)
# {'a': 'b', 'c': 'd'}
print json.loads(js)
# {u'a': u'b', u'c': u'd'}

除此之外,对字符串还可以进行压缩,以节省存储:

1
2
3
4
5
6
7
8
import cPickle as pickle
import zlib

# 序列化,并压缩
compressed = zlib.compress(pickle.dumps(obj))

# 解压缩,反序列化
obj = pickle.loads(zlib.decompress(compressed))

2. Django CSRF

django.middleware.csrf.CsrfViewMiddleware 处理逻辑:

进入 views 函数处理之前,如果 cookies 里面有 csrf token,则将其设置在 request.Meta 中,否则生成一个 token。如果不是 GET、HEAD 等方法则,校验 CSRF。

校验规则:从 Cookie 中取出 csrf token 与 POST 请求中的 csrfmiddlewaretoken 或者 HTTP_X_CSRFTOKEN 进行比较。如果两者相等,则通过校验,否则返回 403。

在返回响应之前,如果设置过 CSRF_COOKIE_USED,则会将 csrf token 设置到 Cookie 中。通常有两种方式设置 CSRF_COOKIE_USED:

  • 直接使用 django.middleware.csrf.get_token 函数获取 csrf token
  • 配置 django.template.context_processors.csrf 上下文处理器,在模板里面渲染 csrf token,实际上还是调用了 get_token 函数

下面是摘取的部分 Django 源码:

 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
30
class CsrfViewMiddleware(object):
    def process_view(self, request, callback, callback_args, callback_kwargs):
        try:
            csrf_token = _sanitize_token(
                request.COOKIES[settings.CSRF_COOKIE_NAME])
            request.META['CSRF_COOKIE'] = csrf_token
        except KeyError:
            request.META["CSRF_COOKIE"] = _get_new_csrf_key()
        if request.method == "POST":
                request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
            if request_csrf_token == "":
                request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
            if not constant_time_compare(request_csrf_token, csrf_token):
                return self._reject(request, REASON_BAD_TOKEN)

    def process_response(self, request, response):
        if request.META.get("CSRF_COOKIE") is None:
            return response

        if not request.META.get("CSRF_COOKIE_USED", False):
            return response
        response.set_cookie(settings.CSRF_COOKIE_NAME,
                            request.META["CSRF_COOKIE"],
                            max_age=settings.CSRF_COOKIE_AGE,
                            domain=settings.CSRF_COOKIE_DOMAIN,
                            path=settings.CSRF_COOKIE_PATH,
                            secure=settings.CSRF_COOKIE_SECURE,
                            httponly=settings.CSRF_COOKIE_HTTPONLY
                            )
        return response

参数解释:

  • max_age: cookie的生命长度,默认为None,浏览器关闭 cookie 立即失效
  • expires: cookie 过期时间时间点,默认为None,浏览器关闭 cookie 立即失效
  • path: Cookie 生效的路径,/ 表示根路径,根路径的cookie可以被任何url的页面访问
  • domain: 默认值为 None,设置该 Cookie 的网页所在的域名None
  • secure: 用来设置 Cookie 只在确保安全的请求中才会发送。当请求是 HTTPS 或者其他安全协议时,包含 secure 选项的 Cookie 才能被保存到浏览器或者发送至服务器。
  • httponly: 只能 http 协议传输,无法被 JavaScript 获取(不是绝对,底层抓包可以获取到也可以被覆盖)默认值 False。

Django 中关于 CSRF 的默认配置:

1
2
3
4
5
6
7
# Settings for CSRF cookie.
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
CSRF_COOKIE_DOMAIN = None
CSRF_COOKIE_PATH = '/'
CSRF_COOKIE_SECURE = False
CSRF_COOKIE_HTTPONLY = False

3. djcelery_crontabschedule already exists 错误

使用版本:

  • Django==1.8.3
  • celery==3.1.18
  • django-celery==3.1.16

升级 django-celery==3.2.2 时,执行 python manage.py migrate,报错:

1
2
3
File "/app/.heroku/python/lib/python2.7/site-packages/pymysql/err.py", line 115, in _check_mysql_exception
    raise InternalError(errno, errorvalue)
django.db.utils.InternalError: (1050, u"Table 'djcelery_crontabschedule' already exists")

在 django-celery 的 GitHub 更新日志中提到:

在 3.1.17 更新版本之后,新增了 Django migrations。

如果已经存在 djcelery_* 等表,则会导致执行 $python manage.py migrate 时报错。升级依赖的版本库时,需要注意版本的兼容性。

4. 如何合并两个 fork 仓库

查看本地远程源:

1
2
3
git remote -v
origin  https://github.com/yourname/celery.git (fetch)
origin  https://github.com/yourname/celery.git (push)

添加需要合并的远程源:

1
git remote add upstream https://github.com/celery/celery.git

查看本地远程源:

1
2
3
4
5
git remote -v
origin  https://github.com/yourname/celery.git (fetch)
origin  https://github.com/yourname/celery.git (push)
upstream        https://github.com/celery/celery.git (fetch)
upstream        https://github.com/celery/celery.git (push)

获取远程源的最新更新:

1
2
3
4
git fetch upstream
From https://github.com/celery/celery
 * [new branch]          var.ci                 -> upstream/var.ci
 * [new branch]          workhorse-pool         -> upstream/workhorse-pool

合并远程 fork 分支到当前分支:

1
git merge upstream/master

5. 监控 Celery 的工具 - Flower

Flower 是基于 Web 的 Celery 监控和管理工具。提供的功能有:

  • 查看 worker 状态和统计信息
  • 关闭和重启 worker 实例
  • 控制 worker 池的大小
  • 显示 task 详细信息
  • 查看当前运行的 task
  • 查看 tasks 的调度
  • 唤醒和终止tasks

安装:

1
pip install flower

运行:

1
python manage.py celery flower

打开:http://localhost:5555,访问:


微信公众号
作者
微信公众号