• 24
  • Oct

终于用完全Django式的方法完成了Admin界面的图片上传与缩略图处理啰!

什么是“django式的方法”,意思就是都是利用Django的类和方法来实现的(除了缩略图处理以外)。因为没做任何其他扩展,所以一些步骤还是需要手动的,比如把图片粘贴进文本区域(-_-#)。

进一步完善后,可以做一个比较自动化的界面来写文章了(像WP一样)!

嗯!最近在完善相当早之前写的TXblog,打算用其来代替现在用的WordPress。

前天写到设计一个模型来存图片,要用ImageField和FilePathField。那天写完后经过反复思考,发现这样是不合适的。应该都用ImageField!

首先来说如何处理缩略图,很简单,用PIL库就可以完成。下面的函数即把给定位置的一张图片处理为480宽度的缩略图(如果小于480才进行处理)。

代码高亮插件有点小问题,把“>”转义掉了。

from __future__ import division
import os
import Image

def make_thumb(path, size = 480):
    pixbuf = Image.open(path)
    width, height = pixbuf.size

    if width > size:
        delta = width / size
        height = int(height / delta)
        pixbuf.thumbnail((size, height), Image.ANTIALIAS)

        return pixbuf

下面是我设计的Media模型,image为图片本身,thumb将在重写的save函数中生成。与Post(即文章)的关系是ForeignKey,即一张图片必对应一篇文章,而文章不一定包含图片。这样设计还能使用Admin的Inline功能与编辑文章的界面显示在一块。请看后面。

还要提提如何手动构建一个ImageField。与CharFiled、IntegerField这类简单的字段不同,CharFiled对应Python的unicode,IntegeField对应int,直接写就可以。而ImageField对应的是ImageFieldFile这个Django自定义的类,所以一定要用Django式的方式构建。

ImageFieldFile继承于FieldFile,建立时需要对象本身,对应的字段和图片的相对路径。所以我就用下面的方法手动建立,并调用save来保存。

import os

from django.db import models
from settings import MEDIA_ROOT
from django.utils.translation import ugettext as _
from django.db.models.fields.files import ImageFieldFile
from utils import make_thumb
from pulog.models import Post

UPLOAD_ROOT = 'upload'
THUMB_ROOT = 'upload/thumb'

class Media(models.Model):
    title = models.CharField(max_length = 120)
    image = models.ImageField(upload_to = UPLOAD_ROOT)
    thumb = models.ImageField(upload_to = THUMB_ROOT, blank = True)
    date = models.DateTimeField(auto_now_add = True)
    post = models.ForeignKey(Post)

    class Meta:
        verbose_name_plural = _('Media')

    def save(self):
        base, ext = os.path.splitext(os.path.basename(self.image.path))
        thumb_pixbuf = make_thumb(os.path.join(MEDIA_ROOT, self.image.name))
        relate_thumb_path = os.path.join(THUMB_ROOT, base + '.thumb' + ext)
        thumb_path = os.path.join(MEDIA_ROOT, relate_thumb_path)
        thumb_pixbuf.save(thumb_path)
        self.thumb = ImageFieldFile(self, self.thumb, relate_thumb_path)
        super(Media, self).save()

    def __unicode__(self):
        return _('%s, uploaded at %s') % (self.title, self.date.strftime('%T %h %d, %Y'))

最后是Admin相关的,在Media这个App下建立一个admin.py,内容是:

from django.contrib import admin
from models import Media

class MediaAdmin(admin.StackedInline):
    model = Media
    admin.site.register(Media)

然后再把Post的admin.py处加一句inlines相关的字段:

from media.admin import MediaAdmin

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'date', 'author')
    radio_fields = {'post_status': admin.VERTICAL,
                    'type': admin.VERTICAL,
                    'comment_status': admin.VERTICAL}
    inlines = [MediaAdmin,]

    class Media:
        js = ( 
            '/static/js/tiny_mce/tiny_mce.js',
            '/static/js/textareas.js',
        )   
        admin.site.register(Post, PostAdmin)

好了!这样的话,两个模型在一个页面里就可以操作了!相当于一边写文章,突然想加图片,那就直接加吧!根据Django Admin的丰富选项,还可以一次性加多张图片,默认是3格。

效果图如下,点击看大图

下次就是把Admin界面进行扩展,实现像WordPress一样方便的图片插入和控制。

Tags: Django.

» You can leave a comment.

6 Comments

  1. 别自已切图啦,看一下 django-dynamic-media-serve 自动生成,要多大弄多大,再加上缓存方面的应用,哪个叫爽呀!

  2. 这个项目开源不,给我看看你的一些写法

  3. @Jason Lee
    Wow! django-dynamic-media-serve这个应用真是不错啊,多谢告之。
    我这个项目放在http://code.google.com/p/pulog/了,应为还比较烂,所以还没公布。
    希望前辈能指出代码中的一些不足。嘿嘿!

  4. 你误解了
    我只是想看一下其它的Django开发人员是如何设计结构的,从而可以在别人的项目中找到更好的做法。

  5. "Django开发人员“,太抬举我了~那就以后相互探讨,呵呵!

  6. I_y

    我有一个想法是在处理缩图时加入一个自定义裁切功能。
    因为有时我们只想显示图片的一部分分,所以用鼠标自定义图片范围进行裁切和缩图处理是个很好的功能,很想实现一下。
    希望大家有更多的讨论:)

Leave a Comment