Kai D
Kai D

Reputation: 153

Overriding the Clean method in my Django ModelForm

The system I am currently working on needs users to enter two emergency contact numbers on registration. I want to implement a check that will ensure that the user is entering a valid number, I've determined this to be a string that begins with either a 0 or a +. To do this, I've tried to override the clean method in the form but it isn't quite working.

This is my forms.py code for the relevant method (Now updated, throwing an error stated below.):

 class UserProfileForm(forms.ModelForm):
   class Meta:
       model = UserProfile
       fields = ('emergcon1', 'emergcon2')
       labels = {
          'emergcon1': ('Emergency Contact Number'),
          'emergcon2': ('Emergency Contact Number 2')
       }

   def clean_emergcon1(self):
      emergcon1 = self.cleaned_data['emergcon1']
      print emergcon1
      if emergcon1[:1] != '0' or '+':
         raise ValidationError(
             _('%(emergcon1)s is not a valid phone number'),
             params={'emergcon1': emergcon1},
         )
      return emergcon1
    def clean_emergcon2(self):
      emergcon2 = self.cleaned_data.['emergcon2']
      if emergcon2[:1] != '0' or '+':
         raise ValidationError(
             _('%(emergcon2)s is not a valid phone number'),
             params={'emergcon2': emergcon2},
         )
      return emergcon2

views.py: def register(request): registered = False

    if request.method == 'POST':
        user_form = UserForm(data=request.POST)
        profile_form = UserProfileForm(data=request.POST)

        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save()

            user.set_password(user.password)
            user.save()

            profile = profile_form.save(commit=False)
            profile.user = user
            profile.save()

            registered = True

        else:
            print(user_form.errors, profile_form.errors)

    else:
        user_form = UserForm()
        profile_form = UserProfileForm()

    return render(request, 'tennis/register.html', {'user_form':user_form, 'profile_form':profile_form, 'registered':registered})

models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)

    emergcon1 = models.CharField(max_length=128, blank=False)
    emergcon2 = models.CharField(max_length=128, blank=False)

    def _unicode_(self):
        return self.user.username
        return self.emergcon1
        return self.emergcon2

My register.html:

{% extends 'tennis/base.html' %}
{% load staticfiles %}

{% block body_block%}

   {% block title_block %}
        Registration
    {% endblock %}

    <body>
        <h1>Register Here</h1>
        {% if registered %}
            <strong> Thank you for registering</strong>
            <a href="{% url 'index' %}"> Return to homepage </a><br />

        {% else %}
            <form id="user_form" method="post" action="{% url 'register' %}">

            {% csrf_token %}

            <!-- displays forms -->
            {{ user_form.as_p }}
            {{ profile_form.as_p }}

            <!-- adds submit button -->
            <input type="submit" name="submit" value="Register" />
        </form>
        {% endif %}
    </body>
{% endblock %}

Full error traceback, error global name '_' is not defined:

    Internal Server Error: /tennis/register/
Traceback (most recent call last):
  File "/home/steph/.virtualenvs/tennis/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/steph/.virtualenvs/tennis/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/steph/Documents/project/tennis_system_project/tennis/views.py", line 29, in register
    if user_form.is_valid() and profile_form.is_valid():
  File "/home/steph/.virtualenvs/tennis/local/lib/python2.7/site-packages/django/forms/forms.py", line 161, in is_valid
    return self.is_bound and not self.errors
  File "/home/steph/.virtualenvs/tennis/local/lib/python2.7/site-packages/django/forms/forms.py", line 153, in errors
    self.full_clean()
  File "/home/steph/.virtualenvs/tennis/local/lib/python2.7/site-packages/django/forms/forms.py", line 362, in full_clean
    self._clean_fields()
  File "/home/steph/.virtualenvs/tennis/local/lib/python2.7/site-packages/django/forms/forms.py", line 383, in _clean_fields
    value = getattr(self, 'clean_%s' % name)()
  File "/home/steph/Documents/project/tennis_system_project/tennis/forms.py", line 30, in clean_emergcon1
    _('%(emergcon1)s is not a valid phone number'),
NameError: global name '_' is not defined

Resolved, fixed by with "import from django.utils.translation import ugettext_lazy as _"

New problem: A number beginning with a 0 is not being recognised as valid. I provided it with 07896428317, and when I click submit it gives me "07896428317 is not a valid phone number".

Upvotes: 0

Views: 5449

Answers (1)

nik_m
nik_m

Reputation: 12106

Since inside the clean() method the to-be-validated fields do not depend on each other you can rewrite the logic like this, i.e use the clean_<field_name> method:

from django.utils.translation import ugettext_lazy as _

class UserProfileForm(forms.ModelForm):
    class Meta:
       # as is

    def clean_emergcon1(self):
        """ Validation of emergcon1 specifically """
        emergcon1 = self.cleaned_data['emergcon1']
        if emergcon1[:1] not in ['0', '+']:
            raise ValidationError(
                _('%(emergcon1)s is not a valid phone number'),
                params={'emergcon1': emergcon1},
            )
        # Always return a value to use as the new cleaned data, even if
        # this method didn't change it.
        return emergcon1

    def clean_emergcon2(self):
        """ Validation of emergcon2 specifically """
        emergcon2 = self.cleaned_data['emergcon2']
        if emergcon2[:1] not in ['0', '+']:
            raise ValidationError(
                _('%(emergcon2)s is not a valid phone number'),
                params={'emergcon2': emergcon2},
            )
        # Always return a value to use as the new cleaned data, even if
        # this method didn't change it.
        return emergcon2

Upvotes: 2

Related Questions