Изменение изображения в Django inlineformset_factory ставит его в конец списка
Предположим, я создаю веб-приложение Django "Как", где пользователи пишут о том, как делать разные вещи, например.
- "Как" сделать веревку
- "Как" сделать глиняный горшок
- "Как" научиться ездить на велосипеде
Вы поняли идею. Я сделал пост создания представления для этого. Теперь, когда участники делают пост. Они добавляют дополнительные изображения в пост
Пример: "Как" сделать веревку
- Это имеет заголовок сообщения = Как сделать веревку
- Post description = "Некоторое описание"
- Опубликовать изображение = основное изображение
Теперь они должны показать изображения шаг за шагом, как сделана веревка
- Изображение 1: Сделай это 1-й
- Изображение 2: Сделайте это вторым
Я использую формы Django вместе с моей моделью поста, чтобы достичь этого. Все работает абсолютно нормально в представлении создания. Нет проблем. Но в обновленном представлении вещи ломаются.
Эта проблема
Проблема в том, что пользователь хочет отредактировать свой пост и переключить изображение № 2. со своего поста на другое изображение. Хотя они изменили 2-е изображение. Это изображение теперь заканчивается в самом конце списка. Заставить пользователя заново загрузить все изображения. Вернуть Орден. Делает мое приложение глючным.
Пример: предположим, что у пользователя есть пост ниже
main post Title
" Some description "
Main Image = Post_image.jpg
1st Image = A.jpg
Image Title
Image description
2nd Image = B.jpg
Image Title
Image description
3rd Image = C.jpg
Image Title
Image description
4st Image = D.jpg
Image Title
Image description
5th Image = E.jpg
Image Title
Image description
6th Image = F.img
Image Title
Image description
Теперь, если я изменил 2-е изображение
B.jpg
вb.jpg
b.jpg перемещается в самый конец списка, и у вас есть порядок A, C, D, E, F, b
Ниже приведены мои модели:
class Post(models.Model):
user = models.ForeignKey(User, related_name='posts')
created_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True,max_length=500)
post_image = models.ImageField()
message = models.TextField()
class Prep (models.Model): #(Images)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_prep')
image = models.ImageField(upload_to='images/', blank=True, null=True, default='')
image_title = models.CharField(max_length=100, default='')
image_description = models.CharField(max_length=250, default='')
sequence = models.SmallIntegerField() ###########################ADDED THIS
class Meta: ###########################ADDED THIS
unique_together = (('post', 'sequence'),) ###########################ADDED THIS
ordering = ['sequence'] ###########################ADDED THIS
Мой пост создать вид
def post_create(request):
ImageFormSet = modelformset_factory(Prep, fields=('image', 'image_title', 'image_description'), extra=12, max_num=12,
min_num=2)
if request.method == "POST":
form = PostForm(request.POST or None, request.FILES or None)
formset = ImageFormSet(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
post_user = request.user
for index, f in enumerate(formset.cleaned_data): #######CHANGED THIS
try: ##############CHANGED THIS
photo = Prep(sequence=index, post=instance, image=f['image'],
image_title=f['image_title'], image_description=f['image_description'])
photo.save()
except Exception as e:
break
return redirect('posts:single', username=instance.user.username, slug=instance.slug)
else:
form = PostForm()
formset = ImageFormSet(queryset=Prep.objects.none())
context = {
'form': form,
'formset': formset,
}
return render(request, 'posts/post_form.html', context)
Мой пост Edit View:
class PostPrepUpdate(LoginRequiredMixin, UpdateView):
model = Post
fields = ('title', 'message', 'post_image')
template_name = 'posts/post_edit.html'
success_url = reverse_lazy('home')
def get_context_data(self, **kwargs):
data = super(PostPrepUpdate, self).get_context_data(**kwargs)
if self.request.POST:
data['prep'] = PrepFormSet(self.request.POST, self.request.FILES, instance=self.object)
else:
data['prep'] = PrepFormSet(instance=self.object)
return data
def form_valid(self, form):
context = self.get_context_data()
prep = context['prep']
with transaction.atomic():
self.object = form.save()
if prep.is_valid():
prep.instance = self.object
prep.save()
return super(PostPrepUpdate, self).form_valid(form)
My Forms.py
class PostEditForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'message', 'post_image', 'group', )
class PrepForm(forms.ModelForm): #####################CHANGED THIS
class Meta:
model = Prep
fields = ('image', 'image_title', 'image_description', 'sequence')
PrepFormSet = inlineformset_factory(Post, Prep, form=PrepForm, extra=5, max_num=7, min_num=2)
*** Нужна помощь в устранении этой проблемы. Пример, если они меняют изображение 2. Затем он должен оставаться в позиции номер 2 и не двигаться в конец списка
1 ответ
В настоящее время вы не сохраняете порядок изображений, полагаясь на то, что они отображаются в том же порядке, в котором они были созданы. Добавление поля в Prep
содержащее место изображения в последовательности изображений поможет:
class Prep (models.Model):
# ...
nr = SmallIntegerField()
#...
class Meta:
unique_together = (('post', 'nr'),)
unique_together
ограничение гарантирует, что каждый номер используется только один раз за пост. Это также позволяет изменять порядок изображений в сообщении без удаления и повторного создания всех Prep
объекты.
При отображении поста, вам придется заказать Prep
объекты по nr
,
Что касается заполнения нового столбца, поскольку нет единого значения по умолчанию, которое имеет смысл, самый простой подход может быть следующим:
- Добавить
nr
поле безunique_together
ограничение иnull=True
первый; перенести изменения. - После миграции переберите существующий
Prep
объекты каждогоPost
в текущем порядке и присвойте им возрастающие номера. - После этого удалите
null=True
, добавлятьunique_together
и мигрировать снова.
unique_together
нужны строковые параметры (он не может получить доступ к полям во внешнем классе); спасибо, что поймали это.
В форме редактирования вы хотите включить новое поле, чтобы пользователи могли поменять местами порядок двух изображений, поменяв местами их индексы. Вы просто должны предоставить им значимое сообщение об ошибке, если они используют дубликаты индексов.
Однако при создании пользователям не нужно явно указывать порядок, поскольку он подразумевается в последовательности изображений в наборе форм. Поэтому я бы предложил изменить цикл for следующим образом:
for index, f in enumerate(formset.cleaned_data):
# ...
photo = Prep(nr=index,
# add all other fields
)
использование nr = index + 1
для удобных для человека индексов, начинающихся с 1. На самом деле, index
или же image_index
может быть лучшим названием для поля, чем nr
,