How can I get self.fields element value in forms file?

Viewed 342

In my forms.py file I have method called r_valid and it is used in views.py file.

from django.shortcuts import render, redirect
from .forms import UserRegisterForm
from django.contrib import messages

def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.r_valid()
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f'Created Account for {username}!')
            return redirect('main')
    else:
        form = UserRegisterForm()

    context = {
        'form': form,
    }
    return render(request, 'register.html', context)

The meaning of it is to ad few more barriers for user which is creating an account. The problem is that in browser it returns an error =>

TypeError at /register/
'CharField' object is not subscriptable

Here you can see that problem is that I can't get self.fields['username']. So please explain how can I get the username value.

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']

    def r_valid(self):
        j = self.fields['username']

        if j[0] in '0123456789':
            raise ValidationError('The username can\'t start with number')
        
        if len(j) < 6:
            raise ValidationError('That username is too short')

        for c in j:
            if c in '@+-/':
                raise ValidationError('Your username can\'t contain @, +, - or /')
    
    def __init__(self, *args, **kwargs):
        super(UserRegisterForm, self).__init__(*args, **kwargs)
        self.fields['username'].help_text = ''
2 Answers

I suggest using self.cleaned_data['username'] to get the value of the field, but I suggest doing that kind of validation inside the forms clean() (or clean_username()) method.

def clean_username(self):
    s = self.cleaned_data['username']

    if s[0] in '0123456789':
        raise ValidationError('The username can\'t start with number')
    
    if len(s) < 6:
        raise ValidationError('That username is too short')

    for c in s:
        if c in '@+-/':
            raise ValidationError('Your username can\'t contain @, +, - or /')

Note: instead of '0123456789' you can also use string.digits.

import string

if s[0] in string.digits:
    ...

You should override the form's clean method to add custom validation to the form. You can access the form's data there, and add your own validation:

def clean(self):
    cleaned_data = super(AddProfileForm, self).clean()
    username = cleaned_data.get('username')

    if username[0] in '0123456789':
        raise ValidationError('The username can\'t start with number')

    return cleaned_data
Related