Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete link disappears in Django admin inline formset if ValidationError raised

I have a form with KeywordInline. When I add new object using the form inlined formset has a js-link to add new form into formset. Newly added forms have a js-enabled delete button (x mark on the right).

KeywordInline

class KeywordInline(admin.TabularInline):
    fields = ('word',)
    model = models.Keyword
    formset = forms.KeywordFromset
    verbose_name = _('Keyword')
    verbose_name_plural = _('Keywords')
    extra = 1
    can_delete = True

    def get_readonly_fields(self, request, obj=None):
        if obj:
            if str(obj.status) == 'Finished':
                self.extra = 0
                self.can_delete = False
                self.max_num = obj.keyword_set.count()
                return ('word',)

        self.extra = 1
        self.can_delete = True
        self.max_num = None
        return []

KeywordFromset

class KeywordFromset(BaseInlineFormSet):
    def clean(self):
        super(KeywordFromset, self).clean()
        formset_keywords = set()
        for form in self.forms:
            if not getattr(form, 'cleaned_data', {}).get('word', None):
                keyword = None
            else:
                keyword = form.cleaned_data['word']
            if keyword in formset_keywords:
                form._errors['word'] = ErrorList([_(self.get_unique_error_message([_('Keyword')]))])
            else:
                formset_keywords.add(keyword)

Now if I hit save button and ValidationError rises those delete buttons disappears from fromset. So if I've added wrong keyword mistakenly I cannot delete it.

Is this normal behaviour? And how can I make delete links persist?

Any help is much appreciated.

like image 224
z4y4ts Avatar asked Sep 26 '11 09:09

z4y4ts


People also ask

What is inline formset in Django?

Django formset allows you to edit a collection of the same forms on the same page. It basically allows you to bulk edit a collection of objects at the same time.

What is formset_ factory?

By default, formset_factory() defines one extra form; the following example will create a formset class to display two blank forms: >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) Iterating over a formset will render the forms in the order they were created.

What is Formset factory in Django?

Django model formsets provide a way to edit or create multiple model instances within a single form. Model Formsets are created by a factory method. The default factory method is modelformset_factory(). It wraps formset factory to model forms. We can also create inlineformset_factory() to edit related objects.


1 Answers

There's no delete link for the inlines that triggered ValidationError since they aren't yet saved to a database, hence no delete link.

I realize it's inconsistent behavior (since you can delete those rows before hitting "save" button, but you can't once they triggered validation errors), but its normal, default way of how Django does it.

To fix this, you could override the template for inline and make the delete buttons appear despite validation errors.

like image 131
WTK Avatar answered Sep 23 '22 14:09

WTK