2

So I have a model called Users and it has a field called first_name.

class Users(models.Model):
    alpha_field = RegexValidator(regex=r'^[a-zA-Z]+$', message='Name can only contain letters')
    user_id = models.AutoField(unique=True, primary_key=True)
    username = models.SlugField(max_length=50, unique=True)
    first_name = models.CharField(max_length=50, verbose_name='first Name', validators=[alpha_field])
    last_name = models.CharField(max_length=50, validators=[alpha_field])
    password = models.SlugField(max_length=50)

and then I created a UsersForm and then in my template page, when displaying any error messages, it doesn't use the verbose name, it uses first_name. For example, my template code for display errors is

{% for field, error in form.errors.items %}
    {% if forloop.counter == 1 %}
        {{ field }}{{ error | striptags }}
    {% endif %}
{% endfor %}

If there is an error in the first_name field, like if I didn't fill it out and still clicked submit, it would display this

"first_nameThis field is required" How do I make it display "First NameThis field is required" instead?

Not that it might make a different but do note that I am using south and schemamigration to update the database, it originally did not have a verbose name but I recently added it and then just saved the file (I didn't do a schemamigration and then migrate the app because it said that no changes seem to have been made).

My UsersForm is this:

from django import forms
from models import Users

class UsersForm(forms.ModelForm):

    class Meta:
        model = Users
        widgets = {'password':forms.PasswordInput()}

    def __init__(self, *args, **kwargs):
        super( UsersForm, self ).__init__(*args, **kwargs)
        self.fields[ 'username' ].widget.attrs[ 'placeholder' ]="Username"
        self.fields[ 'first_name' ].widget.attrs[ 'placeholder' ]="First Name"  
        self.fields[ 'last_name' ].widget.attrs[ 'placeholder' ]="Last Name"
        self.fields[ 'password' ].widget.attrs[ 'placeholder' ]="Password"
        self.fields['first_name'].label='first Name'

my view is here:

def home_page(request):
    form = UsersForm()
    if request.method == "POST":
        form = UsersForm(request.POST)

        if form.is_valid():
            form.save()
    c = {}
    c.update(csrf(request))
    c.update({'form':form})
    return render_to_response('home_page.html', c)
user2817200
  • 1,097
  • 2
  • 18
  • 38
  • Could you show your `UsersForm` form? – alecxe Sep 25 '13 at 22:20
  • Okay just put it up. I also put in all the fields in my model. – user2817200 Sep 25 '13 at 22:28
  • Thanks. Could you add `self.fields['first_name'].label = 'First'` at the end of form's `__init__()` and check if it works? – alecxe Sep 25 '13 at 22:29
  • Okay just did, still didn't change how it looks when an error is raised though :/ it still says "first_nameThis field is required." for some reason – user2817200 Sep 25 '13 at 22:32
  • Take a look, almost exactly your problem: http://stackoverflow.com/questions/18995034/changing-the-field-name-django-uses-when-display-form-error-messages :) – alecxe Sep 25 '13 at 22:38
  • Hm, is there a place where I can find all of the possible errors which can be raised from django CharField forms? because in that thread, the answer just says "if condition".. I know 'required' is a condition but i'm positive that that's not the only time an error message for a charfield form will be raised. The answer also says that the verbose_name should work, or the implicit way should work but neither work for me.. any idea why? Should I look through my entire code to see why this is? What could possibly be making the verbose_name not work? – user2817200 Sep 25 '13 at 22:46
  • Well, I'd try 2 things one by one, just to find the culprit: 1. remove the validator from the model and from the first name field; 2. comment out `__init__()` of your form. Let me know if any of these options helped. Also, what django version are you using? – alecxe Sep 25 '13 at 22:50
  • Hm, neither worked. I'm using django 1.5.3 – user2817200 Sep 25 '13 at 23:37
  • Thank you, then, could you show the relevant view that creates and processes the form? Also, what if you add `self.fields['first_name'].error_messages = {'required': 'First Name is Required'}` to the end of form `__init__()`? – alecxe Sep 25 '13 at 23:42
  • Also, you mentioned earlier to add a label. How do I access the fields label in a template? field.label didn't work for me. Also, okay so I did do the .error_messages and it did fix that one error and did display "First Name is required".. however, if I want to do it this way, doesn't that mean I have to go through all possible error messages which a charfield can raise and change all of them so that it says "First Name" rather than first_name? I'm willing to do it if there is a place where it lists all the possible error messages which a CharField can raise? – user2817200 Sep 25 '13 at 23:45

2 Answers2

3

form.errors is a dictionary of field NAMES as the keys and error messages as the values. It will not be the verbose_name. You need to get the field from the form, then do field.label for the verbose_name. If you use this snippet for getting an attribute on an object dynamically in a template: https://snipt.net/Fotinakis/django-template-tag-for-dynamic-attribute-lookups/, you can do something like this to get the verbose_name:

{% load getattribute %}

{% for field, error in form.errors.items %}
    {% if forloop.counter == 1 %}
        {% with field_obj=form|getattribute:field %}
            {{ field_obj.label }}{{ error | striptags }}
        {% endwith %}
    {% endif %}
{% endfor %}
jproffitt
  • 6,225
  • 30
  • 42
  • Ah, interesting, okay. so I just copy past that snippet (from lines 1 to 20) in my views.py and then use the code you provided and I can get the verbose name? Or does it get me the label (self.fields['first_name'].label='first Name')? Also, you used {{ field_obj.label }}.. what field can I get from using field_obj? Like, other than the .label attribute since I already know I can access it, is there a place for me to see a list of all the other attributes which I can get? – user2817200 Sep 26 '13 at 22:45
  • 1
    It will be an instance of a `BoundField`. So you can get all the attributes that you normally would on a form field. And you cannot just paste the snippet into your views. It is a template filter. You will need a 'templatetags' folder in your app. Read about custom tags and filters here: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/ – jproffitt Sep 26 '13 at 22:51
  • 1
    Also, the `label` will automatically be the `verbose_name` from the model. You do not need to set the label manually. – jproffitt Sep 26 '13 at 22:52
0

I had similar problem some time ago, this snippet helped me out:

from django import template
from django import forms
from django.forms.forms import NON_FIELD_ERRORS
from django.forms.util import ErrorDict

register = template.Library()

@register.filter
def nice_errors(form, non_field_msg='General form errors'):
    nice_errors = ErrorDict()
    if isinstance(form, forms.BaseForm):
        for field, errors in form.errors.items():
            if field == NON_FIELD_ERRORS:
                key = non_field_msg
            else:
                key = form.fields[field].label
            nice_errors[key] = errors
    return nice_errors

http://djangosnippets.org/snippets/1764/

mariodev
  • 13,928
  • 3
  • 49
  • 61
  • Hm, I will resort to it if there is no other solution but how come the verbose_name isn't even working in the first place :S Also, if I use the snippet, then should I remove the {% if form.errors %} block of code from my template? – user2817200 Sep 25 '13 at 22:39
  • I think `{% if form.errors %}` is irrelevant, the loop will not do anything if is't empty. Regarding verbose_name, I have no idea why it's not working, we should look around django src to find out and do a lot of debugging I guess ;/ – mariodev Sep 25 '13 at 22:52