Скопирую сюда:
Понадобилось мне создать галерею из фотоальбомов и фотографий. Стандартная джангвская админка вобщем-то решает эту задачу. Однако при наполнении сайта тестовыми данными меня несколько утомило загружать файлы по одному, и я начал думать как бы так сделать, чтобы загрузить все фотки разом.
Есть две простых модели Album и Photo отношение один-ко-многии.
models.py
from django.db import models
class Album(models.Model):
title = models.CharField(u'название', max_length=100, blank=True, default='')
image = models.ImageField(u'изображение', upload_to=upload_to)
class Photo(models.Model):
album = models.ForeignKey(Album, verbose_name=u'альбом', related_name='photos')
image = ResizedImageField(u'изображение', upload_to=upload_to)
title = models.CharField(u'название', max_length=255, blank=True, default='')
Дла начала надо добавить в форму возможность выбирать несколько файлов. Для этого я создал свой виджект.
widgets.py
from django.contrib.admin import widgets
from django.utils.safestring import mark_safe
class MultiFileInput(widgets.AdminFileWidget):
def render(self, name, value, attrs=None):
attrs['multiple'] = 'true'
output = super(MultiFileInput, self).render(name, value, attrs=attrs)
return mark_safe(output)
Далее надо прицепить это виджет в админку.
admin.py
class AlbumAdmin(admin.ModelAdmin):
pass
class PhotoAdminForm(forms.ModelForm):
class Meta:
model = Photo
widgets = {'image':MultiFileInput}
class PhotoAdmin(admin.ModelAdmin):
form = PhotoAdminForm
admin.site.register(Album, AlbumAdmin)
admin.site.register(Photo, PhotoAdmin)
Теперь мы можем выбирать в форме множество файлов. Однако это не всё, нужно при сохранении для каждого файл создавать объект класса Photo. Сначала я думал, что придётся переопределять вьюхи, урлы и шаблоны, но оказалось, что достаточно только переопределить одну вьюху.
from django.contrib import messages
from django.shortcuts import redirect
from django.utils.encoding import smart_str
class PhotoAdmin(admin.ModelAdmin):
form = PhotoAdminForm
def add_view(self, request, args, *kwargs):
images = request.FILES.getlist('image',[])
is_valid = PhotoAdminForm(request.POST, request.FILES).is_valid()
if request.method == 'GET' or len(images)<=1 or not is_valid:
return super(PhotoAdmin, self).add_view(request, *args, **kwargs)
for image in images:
album_id=request.POST['album']
try:
photo = Photo(album_id=album_id, image=image)
photo.save()
except Exception, e:
messages.error(request, smart_str(e))
return redirect('/admin/gallery/photo/')
Здесь есть хитрость. Если у страница запрашивается методом GET или пользователь загружет один файл, то мы вызываем метод родительского класса, тем самым избавляя себя от дублирования стандартной логики. А вот если у нас пришел метод POST и выбранных файлов больше одного, то тут мы сохраняем все загруженные файлы.
Собственно все. Теперь махом можно загрузить пачку файлов.