终于用完全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格。