Изменение изображения в Django inlineformset_factory ставит его в конец списка - PullRequest
1 голос
/ 10 марта 2019

Предположим, я делаю "Как" Веб-приложение Django, где пользователи пишут сообщения о как ... делать разные вещи, например.

  • «Как» сделать веревку
  • "Как" сделать глиняный горшок
  • «Как» научиться ездить на велосипеде

Вы поняли идею. Я сделал пост создания представления для этого. Теперь, когда участники делают пост. Они добавляют дополнительные изображения к посту

Пример: «Как» сделать веревку

  • Это имеет заголовок сообщения = Как сделать веревку
  • Опубликовать описание = "Некоторое описание"
  • Опубликовать изображение = Основное изображение

Теперь им нужно шаг за шагом показывать изображения, как изготовлена ​​веревка

  • Изображение 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)

Мой пост Редактировать Просмотр:

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 Ответ

1 голос
/ 14 марта 2019

В настоящее время вы не сохраняете порядок изображений, полагаясь на то, что они отображаются в том же порядке, в котором они были созданы.Добавление поля в Prep, содержащего место изображения в последовательности изображений, поможет:

class Prep (models.Model):
    # ...
    nr = SmallIntegerField()
    #...
    class Meta:
        unique_together = (('post', 'nr'),)

Ограничение unique_together гарантирует, что каждое число будет использоваться только один раз для каждого сообщения.Это также позволяет изменять порядок изображений в сообщении без удаления и повторного создания всех Prep объектов.

При отображении сообщения необходимо упорядочить объекты Prep по nr.

*.1012 *

Что касается заполнения нового столбца, поскольку нет единого значения по умолчанию, которое имеет смысл, простейшим подходом может быть:

  • Добавить поле 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.

...