安装pyenv遇到的问题
在Python多版本环境管理之pyenv中说到使用pyenv, 但没有写安装的过程。本以为按照官网安装即可,后来在给同事安装时,发现了问题。
官网上说,在使用Zsh,需要将环境变量加到~/.zshenv中,而不是~/.bash_profile,但其实这样还是会提示没有安装pyenv。正确的配置是将环境变量加到~/.zshrc中。
在Python多版本环境管理之pyenv中说到使用pyenv, 但没有写安装的过程。本以为按照官网安装即可,后来在给同事安装时,发现了问题。
官网上说,在使用Zsh,需要将环境变量加到~/.zshenv中,而不是~/.bash_profile,但其实这样还是会提示没有安装pyenv。正确的配置是将环境变量加到~/.zshrc中。
在编译Thrift时,遇到src/thrift/transport/TSSLSocket.cpp:33:10: fatal error: ‘openssl/err.h’ file not found问题,按照Mac安装Thrift的Openssl错误解决没有解决问题
最后按照stackoverflow上的解决办法,解决了问题。1
2brew install openssl
./configure LDFLAGS='-L/usr/local/opt/openssl/lib' CPPFLAGS='-I/usr/local/opt/openssl/include'
Fabric用于发布和执行一些系统管理任务,非常方便。
目前[学习笔记](用于发布的脚本如下,很方便。1
2
3
4
5
6
7
8
9
10
11
12
from fabric.api import *
env.hosts = ['43.242.128.158']
env.user = 'dengsl'
def deploy():
code_dir = '/home/dengsl/program/nodejs/blog'
with cd(code_dir):
run("git pull")
#deploy static site
run("hexo clean")
run("hexo g")
run("cp -r public/* /home/dengsl/program/html/blog/note")
之前使用virtualenvwrapper来管理Python虚拟环境,使用Python2.7, 没发现问题。后来公司的新项目都使用Python3.5,此时virtualenvwrapper就不能满足需求了,于是开始使用pyenv。
总的来说, pyenv是用于管理Python版本,而virtualenv用于管理Python虚拟环境,两者结合使用,基本上能满足需求。
Middleware相当于Django的底层插件,用于改变Django的输入和输出。最近遇到一个问题是有一些Android无法显示HTTPS页面中夹带的HTTP图片, 于是想到在返回结果中修改,于是想到Middleware.
编写一个Middleware也比较简单,根据需求定义响应的hook方法就好。这里定义如下1
2
3
4
5
6
7class StaticPathFilter(object):
def process_response(self, request, response):
if not response.streaming:
if request.scheme == 'https':
response.content = re.sub(r"http://static.eyaos.com", r"https://static.eyaos.com", response.content)
return response
我这里是StaticPathFilter放在apps.common.middleware模块里, 把’apps.common.middleware.StaticPathFilter’添加到MIDDLEWARE_CLASSES即可。
context_processors用于给Django模版添加context,例如django.template.context_processors.media用于添加MEDIA_URL,django.template.context_processors.static用于添加STATIC_URL。之所以使用context_processors, 是想全局添加某个变量,而不需要在每个View中添加。
查看django.template.context_processors.static的实现,就可以模仿着写自己的context_processors1
2
3
4
5
6def static(request):
"""
Adds static-related context variables to the context.
"""
return {'STATIC_URL': settings.STATIC_URL}
Docker-Compose是用来定义和管理多个Docker容器的工具,用Python编写,前身是Fig.
使用Compose一般分为三步
目前B7310实验室和爱与生的烦恼就是使用Compose管理的。
环境配置放在Github上。
最近在看Django文档Making queries时看到descriptor, 发现描述器很强大.
Descriptors are a powerful, general purpose protocol. They are the mechanism behind properties, methods, static methods, class methods, and super(). They are used used throughout Python itself to implement the new style classes introduced in version 2.2. Descriptors simplify the underlying C-code and offer a flexible set of new tools for everyday Python programs.
但是我还是不懂为什么需要描述符,直到看了Python描述符(descriptor)解密, 才知道描述符的用途。按照视频中的讲解,在理解一遍,加深印象。
假设在做一个农产品销售系统,每个订单是一个产品,每个产品有description, weight, price三个字段
1 | class LineItem(object): |
但这里存在一个问题,即weight可以为负的。1
2
3
4
5
6>>> raisins = LineItem('Golden raisins', 10, 6.95)
>>> raisins.subtotal()
69.5
>>> raisins.weight = -20 #负值
>>> raisins.subtotal()
-139.0
这是一个严重的问题,亚马逊刚起步时就有这个问题。 在Jeff Bezos and Amazon: Birth of a Salesman里有描述。
传统的做法是添加getter和setter方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class LineItem(object):
def __init__(self, description, weight, price):
self.description = description
self.set_weight(weight)
self.price = price
def subtotal(self):
return self.get_weight() * self.price
def get_weight(self):
return self.__weight
def set_weight(self, value):
if value > 0:
self.__weight = value
else:
raise ValueError('value must be > 0')
if __name__ == "__main__":
raisins = LineItem('Golden raisins', 10, 6.95)
print raisins.subtotal()
raisins.weight
print raisins.subtotal()
这种方法存在一些问题,
好在Python提供更好的解决办法, property是其中一种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
28class LineItem(object):
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
@property
def weight(self):
return self.__weight
@weight.setter
def weight(self, value):
if value > 0:
self.__weight = value
else:
raise ValueError('value must be > 0')
if __name__ == "__main__":
raisins = LineItem('Golden raisins', 10, 6.95)
print raisins.subtotal()
print raisins.weight
print raisins.subtotal()
raisins.weight = -2.0
使用property存在一个问题是,当我们需要对price也做非0限制时,需要重复setter设置。此时Descriptor派上用场了。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
31
32
33
34
35
36
37class Quantity(object):
__counter = 0
def __init__(self):
prefix = '_' + self.__class__.__name__
key = self.__class__.__counter
self.target_name = '%s_%s' % (prefix, key)
self.__class__.__counter += 1
def __get__(self, instance, owner):
return getattr(instance, self.target_name)
def __set__(self, instance, value):
if value > 0:
setattr(instance, self.target_name, value)
else:
raise ValueError('value must be > 0')
class LineItem(object):
weight = Quantity()
price = Quantity()
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
if __name__ == "__main__":
raisins = LineItem('Golden raisins', 10, 6.95)
print raisins.subtotal()
print raisins.weight
print raisins.subtotal()
raisins.weight = -2.0
raisins.price = -1
在Quantity类里, instance是指LineItem实例, owner指LineItem类。
具体查看视频,非常不错。
参考资料
因为服务器上HTTP和HTTPS一起存在,所以分享接口这里出了一些问题。
在调用分享接口生成签名时,签名用的url必须是调用JS接口页面的完整URL,但因为存在http和https两种,而Django其实不知道客户端到底是访问http还是https,所以产生了问题。如果写死http, 则访问https时,微信分享签名出错;相反的,如果写死https, 则访问https时,微信分享签名会出错。有什么解决的办法?
查看request对象,知道scheme这个属性,于是看到SECURE_PROXY_SSL_HEADER设置。
大意就是当在settings里配置了SECURE_PROXY_SSL_HEADER,Django就会到request.META里读取相关参数,如果有设置https,则这是一个https请求。而相关参数需要代理服务器设置,我这里使用Nginx。
于是在Nginx配置里,当访问的是https时,就加上1
proxy_set_header HTTP_X_FORWARDED_PROTO https;
然后在Django的settings配置里加上1
SECURE_PROXY_SSL_HEADER = ('HTTP_HTTP_X_FORWARDED_PROTO', 'https')
这里之所以会多一个HTTP_是因为Django默认会给request.ME如此配置后,request.scheme就会返回http, 当请求是https时,则会返回https。分享的签名正确,问题得到解决。