Skip to content

Recent Articles

25
Nov

在Django的admin表单中显示图片

这几天又在折腾admin这颗Django皇冠上的明珠…
这次折腾的还是跟附件相关,不过主要是图片,也就是在表单里显示上传的图片。

查看了一下Django admin的模板,发现对于表单的处理,只用了几个简单的条件判断和循环:

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<fieldset class="module aligned {{ fieldset.classes }}">
  {% if fieldset.name %}
<h2>{{ fieldset.name }}</h2>
{% endif %}
  {% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
  {% for line in fieldset %}
<div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
      {{ line.errors }}
      {% for field in line %}
          {% if field.is_checkbox %}
              {{ field.field }}{{ field.label_tag }}
          {% else %}
              {{ field.label_tag }}{{ field.field }}
          {% endif %}
          {% if field.field.field.help_text %}
{{ field.field.field.help_text|safe }}
{% endif %}</div>
{% endfor %}
  {% endfor %}
</fieldset>

并没有出现对表单元素的相关处理,也就是说相关表单元素的已经在{{ field.label_tag }}{{ field.field }}中包装好,模板只负责显示,遂转移目标。

翻文档,在ModelAdmin Options里发现formfield_overrides,用法如下:

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
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:

?View Code PYTHON
1
2
3
4
5
6
7
8
def render(self, name, value, attrs=None):
        output = []
        if value and hasattr(value, "url"):
            output.append('%s <img src="%s" alt="" />
%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的代码结构有了进一步的了解,相信以后应用起来要轻松很多了~~

22
Nov

CupTool

人生是一只茶几,上面放满了杯具。而本身就是杯具的我们还非加上茶叶自以为与别人没有茶具,结果人人都说咱现在要具就用餐具。

我们在沉默中灭亡,成了文具;在沉默中爆发,成了火炬。我们想明哲保身,都成了面具。我们想一鸣惊人,都成了京剧。不能再次相聚,执手相看泪眼,成了默剧。

生活是自己的杯具,别人眼里的洗具。

我跟上帝说我渴了,于是上帝给了我一大堆杯具。

昨天晚上刚吃完晚饭,就来电话说从南宁回来玩的家志请吃饭,我瞬间就杯具了——刚才为虾米要吃的那么饱呢…
晚上5个人窝在房间里聊天扯到半夜3点,出了学校,才知道柴米油盐贵,每天掐着手指头算钱,一分钱都没敢多花…
毕业之后,我们宿舍的人,基本上都留在桂林,几个月的经历,大家的想法都成熟了很多,也都有了新的想法,也许农历年后,大家就都要离开桂林了。
可是谁知道呢,就像四年前我压根没想留桂林一样。世事难料,谁也不知道后面会发生什么事情。

到手的鸭子飞了几只。银行卡已经是负数,压力越来越大…
创业的心酸,只有经历过之后才知道。

25
Oct

Mountain climbing and Graffiti

小媳妇老早就说要去爬尧山了,前段时间实项目上是在忙不过来,加上一直加班,精力也不咋地,所以一直没去,然后昨天准备去的,结果半夜下雨,我听到雨声就跟抓到救命稻草,就跟媳妇儿说下雨了,明天再去,然后对倒头就睡了,结果白天艳阳高照,理甚亏,下午赶忙跑公司加班,修bug若干= =!

今天天气还不错,6点多爬起来,就带着媳妇儿去爬山了。恩,跟大多数人一样,开始那个高兴劲哈,然后爬了一半…“再也不来爬了…..”,好歹咱也曾经是每周都来怕一次的人,连哄带拖,花了差不过两个小时总算到了山顶,然后又花了差不多3个小时走后山的公路下来,好歹咱也是曾经每周去走一次的人….咳….半路饿昏了还闹别扭= =!

回到理工大的时候已经下午2点多了,去吃饭的路上看到了墙上的涂鸦,其实这个涂鸦已经出来1个多月了,不过都没来拍,刚好身上带了相机,随手拍下来。不过中间还有有办证的广告了,唉….

话说这墙上的涂鸦从我大一进学校开始就有了,基本是每个学期都会更新几次,不过到现在为止还没晓得是哪些人做的= =!

不过不得不承认的是,我一点深度都没有,这玩意儿完全看不懂….

18
Oct

乔巴看到肯定会哭鼻子的…

其实很早就想拍下来了,因为每天坐车上下班都看到,有个店面拿了《海贼王》里的乔巴的头像做logo,这个也就算了,硬是活生生把人家一个驯鹿搞成鸭子= =!不过因为车上一直拍不到,然后前些天跟小媳妇去逛街,遇到另外一家分店,好吧,不能放过,我是被雷到了反正….

P.S 相片是用M8拍的,时间证明M8的相机在晚上的的表现能力确实不咋地…』
P.S.P 本文乃周日加班无聊之作…

15
Oct

Rename uploaded files in Django admin site

Django的admin site组件被誉为“皇冠上的明珠”,经过最近的体验,确实很大的提高开发速度,不过应为其高定制性,似乎也给灵活性方面带来了一些困扰。

Django的文件上传,默认是保存为原文件名的,我点破鼠标也没找到Django提供的重命名方法,百google毒之后发现似乎只能重写相关的field,或者直接重写FileSystemStorage来实现对上传文件的重命名。不过按照目前的需求,在admin中重写相关的field更现实/灵活一点,所以翻了会Django的源码,稍微重写了一下。

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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来做后台就是为了加快开发速度,不能因为这个又耽误了不是~~~