菜鸟网络工程师的成长笔记——第6天(2016.08.23)
有时候感觉自己跟周围同事比起来实在是太次了,啥也不懂,然后用一种方式安慰自己,他们只是比我更熟悉业务。当初在通信公司,业务就一些通信协议,现在在互联网公司,业务其实就是一些HTTP的知识,一些服务器知识、前后台交互、部署等等。无他,唯手熟尔。
9.添加MEDIA_ROOT后,访问报错:AttributeError: ‘tuple’ object has no attribute ‘startswith’
问题类型:Python
解决状态:已解决
问题描述
在Django的settings中添加MEDIA_ROOT变量如下:
MEDIA_ROOT = os.environ.get("MEDIA_ROOT", "/tmp"),
,运行报错
AttributeError: ‘tuple’ object has no attribute ‘startswith’
问题解决
各种添加打印,发现settings.MEDIA_ROOT就是个tuple,以为是Django的某机制将其存为tuple了,翻Django的文档也没找到线索,最后还是stackoverflow给出了答案,竟然有人跟我犯了同样的错误,在最后加了逗号。原来Python的这种简单的赋值语句,只要在最后加逗号,就被当做tuple了。
10.用户上传头像功能在本地调试可用,发布到生产环境有问题
问题类型:Django
解决状态:解决中
问题描述
之前在本地环境下调试好了用户上传头像的功能,方法是用户将图片上传到static路径下,然后用数据库的一个字符串字段存放图片的相对路径名,然后在模板中src属性中取出这个路径名。这个方法在本地没什么问题,但是发布到生产环境就不行了。
问题解决
之所以放到生产环境无效,是因为生产环境下并不是直接在static路径下找静态文件,而是将静态文件收集到一个指定的路径下,然后用户再向原来指定的路径上传,也就找不到了。
1.重新定义数据库字段
其实Django模板提供了一个ImageFiled的字段,专门用于上传图片(类似的,还有一个FileFiled字段用于上传文件)。于是将原本用CharField定义的字段重新定义为:
# 头像
#headshot = models.CharField(max_length=100, default="/static/img/headshot/default_headshot.jpg")
headshot = models.ImageField(upload_to='/headshot/')
这个upload_to参数据说可以指定上传路径,但是我貌似没有用到这个功能,而是自己进行了存储,一会儿可以看到。执行make migration, migrate之后,发现数据库里面该字段其实就是一个CHAR(100),用来存放的就是文件名的字符串。
2.设置MEDIA_ROOT和MEDIA_URL
要在settings.py中添加两个变量:
MEDIA_ROOT = os.environ.get("MEDIA_ROOT", "/tmp")
这个变量是一个绝对路径,用于存放上传的图片,像上面这样,如果不设环境变量,就把图片存放在/tmp路径下。
MEDIA_URL = "/media/"
这个变量用于设定通过URL访问图片时的前导字段,比如我们讲一张名为’a.jpg’的图片存放在了/tmp路径下,我们可以通过如下url进行访问:
172.0.0.1/media/a.jpg
这个url就可以访问到/tmp/a.jpg
3.添加media中间件
要在模板中使用{{ MEDIA_URL }}来获取MEDIA_URL变量,还需要添加一个中间件:
在settings.py的TEMPLATE中添加:
"django.core.context_processors.media",
4.添加测试环境下的url
只是做了如上述的动作,还是不能访问图片,需要添加测试环境下的url,在根url.py文件中添加:
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root':settings.MEDIA_ROOT}),
...
]
这样就可以在测试环境下使用了,但是如何在生产环境下设置,是否只需要设置MEDIA_ROOT环境变量就可以了,还要拭目以待。
5.在视图函数中保存图片
这个貌似ImageFiled字段提供了特定的方法,但是还没搞懂怎么用,还是使用了传统的保存方法,然后将图片名保存到数据库中:
profile = Profile.objects.get(user=request.user)
if request.method == 'POST':
form = ImageUploadForm(request.POST, request.FILES)
if form.is_valid():
img = request.FILES['image']
extention = file_extension(str(img)) # 获取上传图片的后缀名
icon = settings.MEDIA_ROOT + '/' + str(user) + extention # 头像以'用户名.后缀名'的形式存放在[settings.MEDIA_ROOT]/路径下
destdion = open(icon, 'wb+')
for chunk in img.chunks():
destdion.write(chunk)
destdion.close()
if profile:
profile.headshot = str(user) + extention
profile.save()
else:
pass # 未知错误
6.在模板中引用图片
在模板中可以使用{{ MEDIA_URL }}来获取settings.MEDIA_URL变量,用于组成正确的URL向服务器获取图片,可以在模板中使用如下形式:
src="{{ MEDIA_URL }}{{ user.profile.headshot }}"
其实在这个实例中,{{ MEDIA_URL }}就是’/media/’