9

I'd like to create widgets that add specific classes to element markup when the associated field has errors.

I'm having a hard time finding information on how to check whether a field has errors associated with it, from within widget definition code.

At the moment I have the following stub widget code (the final widget will use more complex markup).

from django import forms
from django.utils.safestring import mark_safe
class CustomTextWidget(forms.Widget):
        def render(self, name, value, attrs):
            field_has_errors=False # change to dynamically reflect field errors, somehow
            if field_has_errors:
                error_class_string="error"
            else:
                error_class_string="" 
            return mark_safe(
            "<input type=\"text\" class=\"%s\" value=\"%s\" id=\"id_%s\" name=\"%s\">" % (error_class_string, value, name, name)
            )

Can anyone shed light on a sensible way to populate the field_has_errors Boolean here? (or perhaps suggest a better way to accomplish what I'm trying to do). Thanks in advance.

bitbutter
  • 580
  • 5
  • 15

2 Answers2

11

As Jason says, the widget has no access to the field itself. I think a better solution though is to use the cascading nature of CSS.

{% for field in form %}
<div class="field{% if field.errors %} field_error{% endif %}">
{{ field }}
</div>
{% endfor %}

Now in your CSS you can do:

div.field_error input { color: red }

or whatever you need.

shabeer90
  • 5,161
  • 4
  • 47
  • 65
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • This is definitely the way to go and is actually the approach I always take in my own work. The example I provided was cobbled together in an effort to show the passing of attributes to widgets (not just custom widgets), however it should be avoided as it is not DRY. – Jason Leveille Jul 10 '10 at 20:10
  • two years later it helped me. Thank you :) – Houman Jul 07 '12 at 20:58
  • 1
    Why don't they pass the error information to the widget though? Seems like it would be reasonable to me, since it's common to render errors right next to the input for the field. – Andy Oct 27 '16 at 16:27
5

The widget has no knowledge of the field to which it is being applied. It is the field that maintains information about errors. You can check for error_messages in the init method of your form, and inject an error class to your widget accordingly:

class YourForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(YourForm, self).__init__(*args, **kwargs)    
        attrs = {}
        if self.fields['your_field'].error_messages is not None:
            attrs['class'] = 'errors'
        self.fields['your_field'].widget = YourWidget(attrs=attrs)
Jason Leveille
  • 1,190
  • 5
  • 10