Search code examples
djangodjango-admindjango-formsdjango-validation

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.


Solution

  • 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.