这几天又在折腾admin这颗Django皇冠上的明珠...
这次折腾的还是跟附件相关,不过主要是图片,也就是在表单里显示上传的图片。
查看了一下Django admin的模板,发现对于表单的处理,只用了几个简单的条件判断和循环:
并没有出现对表单元素的相关处理,也就是说相关表单元素的已经在{{ field.label_tag }}{{ field.field }}中包装好,模板只负责显示,遂转移目标。
翻文档,在ModelAdmin Options里发现formfield_overrides,用法如下:
from django.db import models
from django.contrib import admin
Import our custom widget and our model from where they're defined
from myapp.widgets import RichTextEditorWidget
from myapp.models import MyModel
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': RichTextEditorWidget},
}
也就是说可以用widget的方式来进行包装,继续翻Django的代码,发现奥秘:在Django/contrib/admin/widgets.py中,有对各种input的包装!哈,有戏,于是自己写了一个widget,其实也就是原本照搬Django自带的那个AdminFileWidget,将其中的a改成img:
def render(self, name, value, attrs=None):
output = []
if value and hasattr(value, "url"):
output.append('%s
%s ' %
(_('Currently:'), value.url, _('Change:')))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
然后在formfield_overrides中填写自己写的这个widget即可。
但是这样做有个问题,就是使用formfield_overrides处理的话,表单中所有的同类型input(比如上面的TextField)都会被这么包装一次,这显然是不行的,那怎么解决呢?
别着急,在在ModelAdmin Options里还有一个参数,就是ModelAdmin.form,可以自定义一个form,而不是Django admin默认调用model生成表单,那就好办了,参照这里就可以很简单的重写指定的一个input,避免上面的情况~~~
应为Django的资料相对来说比较少(特别是中文资料),加上自己对Django了解也比较肤浅,实现上面的这个效果费了小周折,不过通过这次,对Django的代码结构有了进一步的了解,相信以后应用起来要轻松很多了~~
Django的admin site组件被誉为“皇冠上的明珠”,经过最近的体验,确实很大的提高开发速度,不过应为其高定制性,似乎也给灵活性方面带来了一些困扰。
Django的文件上传,默认是保存为原文件名的,我点破鼠标也没找到Django提供的重命名方法,百google毒之后发现似乎只能重写相关的field,或者直接重写FileSystemStorage来实现对上传文件的重命名。不过按照目前的需求,在admin中重写相关的field更现实/灵活一点,所以翻了会Django的源码,稍微重写了一下。
from django.db.models.fields.files import ImageField, ImageFieldFile
class CoverImageFieldFile(ImageFieldFile):
def save(self, name, content, save=True):
import time, random
parts = name.split(".")
new_name = time.strftime('%Y%m%d%H%M%S')
new_name += '%d' % random.randint(1000,9999)
new_name += '.%s' % parts[-1]
super(CoverImageFieldFile, self).save(new_name, content, save)
class CoverImageField(ImageField):
attr_class = CoverImageFieldFile
def __init__(self, *args, **kwargs):
super(CoverImageField, self).__init__(*args, **kwargs)
我这里按照当前时间+四个随机数的方式对上传图片重命名,然后把新的文件名作为参数,直接调用父类的方法来保存文件就OK了。使用的时候使用这个自定义的field替代Django的,就能实现上传之后重命名
我个人还是比较喜欢对原有类库影响非常小的方式来实现需要的功能,这样在版本升级的时候就不用头皮发麻的再修改一次(没办法,我的版本控属性太高)。
现在对Django的了解还很少,或者还所很肤浅,因此对于一些想法的实现估计很幼稚。慢慢来吧,下一步是要实现admin里的图片预览和异步上传...对于目前阶段的我来说,比较艰巨阿。今天考虑,这些高级的实现推后才行,因为项目时间已经不允许了,只能留在上线后去实现这些。一口吃不成胖子哈,原本使用Django来做后台就是为了加快开发速度,不能因为这个又耽误了不是~~~
不得不承认,TualatriX忽悠人的本事相当了得,在成功忽悠我用上Git之后,我又走上了Python的不归路...(其实我也忘记到底是先Python的还是先Git的,囧...),话说在把我忽悠上Git之后,他自己又叛逃到Bzr去了,这个花心的男人....
OK,不瞎扯了,来说说我的这个项目。
我的上一篇日志不是说开始用M8发布图片了不是,然后发现Flickr的移动版本不能直接上传,另外再去twitter同步信息也相当烦躁(特别我还是用手机来操作),虽然Twitpic是个不错的选择,但是这个东西不能拿来当相册使...所以还是觉得很不爽= =!
恰好现在被TualatriX忽悠到Python+Git上来,正愁没东西练手(开始准备拿高中班里的同学录开刀(PHP练手用的,半成品,相册基于Yupoo的API),但是想想那个快淘汰的东西,没有太大的开发价值了...),然后今天就决定,在github上弄这么个项目来实践,名字呢,取的比较土,Flickr+Twitter = Flitter,主要针对移动设备的图片发布并推到Twitter,哈哈,就是这样子~~~
项目在github的地址是http://github.com/lfeng/flitter,flitter v0.1要实现的功能很简单,不过因为Python和Django都还是入门级别,所以正式上线估计还得一整子,因为公司的项目现在也忙着重构优化,已经够头疼的,只能用晚上的那点可怜的休息时间倒腾倒腾,走过路过的大哥大姐大叔大妈不要笑话我就得,哈哈~~~
okay,扯完,闪去继续学Django~~~
Python Web开发——Django...在TualatriX的引诱下,开始接触Python,不过自己一直比较擅长的是Web开发,所以就没去倒腾pygtk啦,拿自己擅长的东西上手嘛,于是就开始边Python边Django。看Django官方的教程确实有点头大,谁让我鸟语太烂呢(考个CET-4都还差9分,失败...),上当当找书咯,找着这本,看介绍还不错的样子哈...
然后书昨天到了,偶的神哎,书一到手大失所望:这书也太山寨了...
首先是封面,印刷比现在书市上大部分盗版书都差!山寨的没话说了。然后到纸张,那个薄的,都可以看到背面的字,对阅读造成了很大的干扰,节省成本也不是这么干的吧,而且本来价钱就不便宜了...
昨晚回来大概翻了三分之一不到。内容实在有点那个。目前看的这些,除去python入门,Django的部分实在跟官方网站的教程没有的太大的区别,还不如官方教程的详尽。。。不知道后面的内容怎么样...囧rz....
囧囧更健康...看样子我还是要看鸟语的PDF不叫舒服...TX共享给我那么多不看都浪费了哈....