UpdateView очищает удаленную форму, но фактически не удаляет ее

У меня есть formset modelforms, содержит ImageField. После установки флажка "Удалить" рядом с начальной формой и кнопки "Отправить" - у меня такое же количество форм в наборе форм и такое же количество исходных форм, но те, которые были "удалены", теперь не имеют значения и не имеют флажка удаления (флажок включен в Панель администратора, я предполагаю, что это виджет рендеринга). Что я делаю не так?

Mixin для объединения создания и обновления представлений:

class HumanAddEditMixin(object):
    u"""
    """
    form_class = HumanForm
    model = Human
    template_name = 'human/add_edit.html'
    object = None

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(HumanAddEditMixin, self).dispatch(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        if self.object:
            form = self.form_class(request.POST, instance=self.object)
            sign_formset = SignFormSet(request.POST, request.FILES, instance=self.object)
            description_formset = DescriptionFormSet(request.POST, request.FILES, instance=self.object)
            doc_formset = DocFormSet(request.POST, instance=self.object)
        else:
            form = self.form_class(request.POST)
            sign_formset = SignFormSet(request.POST, request.FILES)
            description_formset = DescriptionFormSet(request.POST, request.FILES)
            doc_formset = DocFormSet(request.POST)

        if form.is_valid() and sign_formset.is_valid() and description_formset.is_valid() and doc_formset.is_valid():
            return self.form_valid(form, sign_formset, description_formset, doc_formset)
        else:
            return self.form_invalid(form, sign_formset, description_formset, doc_formset)

    def form_valid(self, form, sign_formset, description_formset, doc_formset):
        if not self.object:
            self.object = form.save()
            sign_formset.instance = self.object
            description_formset.instance = self.object
            doc_formset.instance = self.object

        sign_formset.save()
        description_formset.save()
        doc_formset.save()

        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, sign_formset, description_formset, doc_formset):
        return self.render_to_response(
            self.get_context_data(
                form=form,
                sign_formset=sign_formset,
                description_formset=description_formset,
                doc_formset=doc_formset
            )
        )

    def get_success_url(self):
        return reverse('human:list')

CreateView выглядит так, как будто работает нормально:

class HumanAddView(HumanAddEditMixin, CreateView):
    def get_context_data(self, **kwargs):
        context = super(HumanAddView, self).get_context_data(**kwargs)

        context['sign_formset'] = SignFormSet(instance=self.model())
        context['description_formset'] = DescriptionFormSet(instance=self.model())
        context['doc_formset'] = DocFormSet(instance=self.model())

        return context

UpdateView:

class HumanUpdateView(HumanAddEditMixin, UpdateView):
    pk_url_kwarg = 'human_id'

    def dispatch(self, request, *args, **kwargs):
        self.object = get_object_or_404(self.model, pk=kwargs[self.pk_url_kwarg])

        return super(HumanUpdateView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(HumanUpdateView, self).get_context_data(**kwargs)

        context['sign_formset'] = SignFormSet(instance=self.object)
        context['description_formset'] = DescriptionFormSet(instance=self.object)
        context['doc_formset'] = DocFormSet(instance=self.object)

        return context

Объявление Formsets:

SignFormSet = inlineformset_factory(Human, HumanSignImage, form=HumanSignImageForm, extra=1)
DescriptionFormSet = inlineformset_factory(Human, HumanDescriptionImage, form=HumanSignImageForm, extra=1)
DocFormSet = inlineformset_factory(Human, HumanDocImage, form=HumanDocImageForm, extra=1)

Одна из моделей с изображением (что в SignFormSet) и его модель (только с помощником хрустящих форм):

class HumanSignImage(models.Model):

    human = models.ForeignKey('Human', related_name='sign_images')
    image = models.ImageField(upload_to=get_file_path, verbose_name=u'', blank=True, null=True)

    def __unicode__(self):
        return self.image.name

class HumanSignImageForm(CommonImageModelFormWithHelper):
    class Meta:
        model = HumanSignImage

1 ответ

Решение

Наконец, я понял, что моя проблема в том, что на панели администратора есть два типа флажков: очистить и удалить. И по какой-то причине (с can_delete = True crispy-forms не отображает флажок удаления здесь есть ответ) я ошибся, что clear было удалить.

Или (без crispy-форм) переопределить виджет ClearableFileInput (без clear, но с delete), что-то вроде этого:

class ImageFileInput(ClearableFileInput):
    template_with_initial = '{initial} {input} {delete}'

    def delete_checkbox_name(self, name):
        """
        Given the name of the file input, return the name of the DELETE checkbox
        input.
        """
        tmp_list = name.split('-')
        del tmp_list[-1]
        delete_checkbox_name = '-'.join(tmp_list)

        return delete_checkbox_name + '-DELETE'

    def delete_checkbox_id(self, name):
        """
        Given the name of the delete checkbox input, return the HTML id for it.
        """
        return 'id_' + name

    def render(self, name, value, attrs=None):
        substitutions = {}
        template = '{input}'
        substitutions['input'] = FileInput().render(name, value, attrs)

        if value and hasattr(value, "url"):
            template = self.template_with_initial
            substitutions['initial'] = format_html(
                self.url_markup_template,
                value.url,
                force_text(value)
            )

            checkbox_name = self.delete_checkbox_name(name)
            checkbox_id = self.delete_checkbox_id(checkbox_name)
            substitutions['delete'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})

        return mark_safe(template.format(**substitutions))
Другие вопросы по тегам