Как загрузить несколько изображений с флагами в Django
Я создаю веб-страницу, на которой автор блога может писать контент и загружать изображения. Используя поле изображения, я позволяю автору загружать несколько изображений и с помощью некоторой логики Javascript отображаю изображения перед загрузкой. Под каждым изображением у меня есть флажок, который указывает, является ли это изображение главным в посте (например, первым в слайд-шоу и используется в качестве миниатюры самого поста).
На этой странице я показываю две формы с общей кнопкой отправки, и она работает нормально.
Мои проблемы начинаются, когда я пытаюсь сохранить изображение, а также указать, является ли оно основным.
Моя модель изображений имеет несколько полезных методов, свойство thumbnail для Django admin и метод save, который будет устанавливать все изображения для поста в false, перед редактированием/добавлением нового main_image. Мне пришлось включить логику аргумента фиксации из-за моих экспериментов. Пожалуйста, не обращайте на это внимания. Модель включает 3 поля: изображение, флаг main и внешний ключ к посту следующим образом:
class PostImages(models.Model):
"""
Post images for the blog app.
"""
image = models.ImageField(
verbose_name=_("Изображение"),
upload_to='blog/images/',
blank=False,
null=False,
default='blog/images/default.jpg'
)
post = models.ForeignKey(
to=Post,
on_delete=models.CASCADE,
verbose_name=_('Статия')
)
main_image = models.BooleanField(
default=False,
verbose_name=_('Основно изображение')
)
class Meta:
verbose_name = _('Изображение')
verbose_name_plural = _('Изображения')
permissions = [
('can_manage_post_image', _('Може да управлява изображенията на публикациите')),
('can_add_post_image', _('Може да добавя изображения към публикациите')),
]
def __str__(self):
return f"{self.post.title} - {self.image}"
def get_absolute_url(self):
return f"/blog/post/image/{self.id}"
def get_edit_url(self):
return f"/blog/post/image/{self.id}/edit"
def get_delete_url(self):
return f"/blog/post/image/{self.id}/delete"
def get_image(self):
return mark_safe(f'<img src="{self.image.url}" width="100" height="100" />')
def get_image_url(self):
return self.image.url
@property
def thumbnail_preview(self):
if self.image:
return mark_safe('<img src="{}" width="400" height="auto" />'.format(self.image.url))
return ''
def save(self, *args, **kwargs):
if self.main_image and kwargs.get("commit", True):
PostImages.objects.filter(post=self.post).update(main_image=False)
kwargs.pop("commit", None)
super().save(*args, **kwargs)
Я также использую модельную форму. В модельной форме я не запрашиваю должность, потому что она еще не создана. Моя идея заключалась в том, чтобы заполнить должность на этапе сохранения, следуя процессу:
- сохранить пост
- сохранить изображения Для меня это логичный ход, но зная, сколько времени это стоило мне до сих пор -> возможно, это не лучший ход.
class PostImagesForm(forms.ModelForm):
"""
Form for uploading images for posts.
"""
image = forms.ImageField(
label='Снимка',
widget=forms.ClearableFileInput(
attrs={
'class': 'form-control',
'multiple': True,
}
)
)
main_image = forms.BooleanField(
label='Основна снимка',
required=False,
widget=forms.CheckboxInput(
# attrs={
# 'class': 'form-control',
# }
)
)
class Meta:
model = PostImages
fields = ['image', 'main_image']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['image'].required = False
def save(self, commit=True):
"""
Save the form and return the created or edited post.
"""
post_image = super().save(commit=False)
post_image.save(commit=commit)
return post_image
def clean(self):
"""
Clean the form and return the cleaned data.
"""
cleaned_data = super().clean()
return cleaned_data
Пока что, так .... хорошо, я полагаю.
Вот вопросы:
- Как сказать Django, что я загружаю пару полей (файл и чекбокс)?
- Как передать экземпляр поста изображению?
- Почему мои файлы запроса пустые?
- Как я должен группировать пары изображение-чекбокс? Это что-то внутри html?
- Я использую несколько форм под одной кнопкой отправки. В какой-то момент я заигрался и удалил
enctype="multipart/form-data"
из тега формы. (oops) - Мой javascript имел странное поведение, потому что он подкачивал изображение как
"data:sjdfhsdkjbfksd"
в мой идентификатор для чекбокса. И снова ошибка новичка. Я обнаружил ее, когда начал приклеиватьconsole.log()
ко всему и вся. - Если вы похожи на меня (основной язык - Python, а JS - нечто случайно известное), помните - в браузере есть фантастический отладчик для JS, под
sources
. - Области действия JS странные, они не такие, как в Python. При использовании отладчика вы увидите, что циклы, выполняющие действия и вызывающие функции событий, всегда будут делать все вне функций событий, а затем переходить к вашей функции событий. Вы можете передавать вещи путем переназначения в операторах
var
, но будьте готовы к тому, что на вас накричит парень из JS.
Я пытался использовать саму форму, но она пропускает экземпляр поста.
Я пытался перебрать все файлы, но они пустые.
Я попытался перебрать поля формы, но не вижу всех загруженных файлов.
Если кому-то это когда-нибудь понадобится:
Я обнаружил несколько проблем, которыми, как мне кажется, было бы полезно поделиться.