0

I am trying to add an error class to fields of a each form in a formset if a custom clean method detects errors. This does look to do the trick, I load the page, and the field does have the error class in it. but when in the template I add a custom filter to add a form-control class, everything falls apart.

# in my inlineformset:
def clean(self, *args, **kwargs):
    
    if any(self.errors):
        errors = self.errors
        return
    
    ## 1) Total amount
    total_amount = 0
    for form in self.forms:
        if self.can_delete and self._should_delete_form(form):
            continue

        amount         = form.cleaned_data.get('amount')
        total_amount  += amount

    if total_amount> 100:
        for form in self.forms:
            form.fields['amount'].widget.attrs.update({'class': 'error special'})
        raise ValidationError(_('Total amount cannot exceed 100%'))

And, here is my code for the custom filter:

@register.filter(name = 'add_class')
def add_class(the_field, class_name):
    ''' Adds class_name to the string of space-separated CSS classes for this field'''

    initial_class_names = the_field.css_classes()    ## This returns empty string, but it should return 'error special'


    class_names = initial_class_names + ' ' + class_name if initial_class_names else class_name

    return the_field.as_widget(attrs = {'class': class_names,})

And, in my template:

{# {{ the_field|add_class:"form-control"}} #}   #<- This adds the form-control, but removes the other classes added in the clean method
{{ the_field }}      {# This shows the two classes for the offending fields, 'error special' #}

I think the problem is with the .css_classes() method which does not bring in the classes defined on the form. Remember, these classes have been set on these fields and rendering {{ the_field }} shows the classes were correctly passed down to the template. So, then the question is whether I am using the correct method .css_classes() or if I should use another method?

EarlyCoder
  • 1,213
  • 2
  • 18
  • 42
  • Does this answer your question? [Adding css class to field on validation error in django](https://stackoverflow.com/questions/4847913/adding-css-class-to-field-on-validation-error-in-django) – Nicolae Sep 02 '20 at 16:47
  • No! I did come across that SO post prior to posting my question. My problem has to do with the formset cleaning, so ```error_css_class ``` does not apply to it as that will be set if the field in an individual form has a problem. The individual forms in my modelformset are just fine, but the total added amount from multiple form triggers the error. So, unless there is another error_css_class for modelformset, and not for modelform, this does NOT apply to my case. Other solutions in that post were also tried and incorporated, but the problem persists – EarlyCoder Sep 02 '20 at 17:28

1 Answers1

0

I was able to add class error to the field using .add_error method of the form. Although this works around the problem, I would still appreciate if anyone can explain how come the the_field.css_classes() returned an empty string instead of what was set in the clean method:

form.fields['amount'].widget.attrs.update({'class': 'error special'})

The problem with add_error method is that it only adds the class error. But, what if I'd want to add another class special to the widget? So, the original problem still needs an answer. My solution here then is just a solution and not the solution:

# in my inlineformset:

def clean(self, *args, **kwargs):

if any(self.errors):
    errors = self.errors
    return

## 1) Total amount
total_amount = 0
for form in self.forms:
    if self.can_delete and self._should_delete_form(form):
        continue

    amount         = form.cleaned_data.get('amount')
    total_amount  += amount
    if total_amount > 100:
        msg = 'This field throw the amount over the 100% limit'
        form.add_error('amount', msg)

if total_amount> 100:
    raise ValidationError(_('Total amount cannot exceed 100%'))
EarlyCoder
  • 1,213
  • 2
  • 18
  • 42