'NoneType' object is not callable for some reason

I have this view for user registration. If the method is GET, just render the form.

If the method is POST, create a form with POST data and try to validate it. Show validation errors if the fields are invalid.

If the form is valid, check if user with the email is already registered. If not, create a new user and login. Otherwise show an error in the page.

# 4 Authentication & authorization
def register(request: HttpRequest):
    if request.method == "POST":
        form = RegisterForm(request.POST)

        # 2 Input validation & sanitization
        if form.is_valid():
            if not user_repo.is_registered(form.cleaned_data["email"]):
                user = user_repo.create(form.cleaned_data)
                login(request, user)
                
                # 5 Security logging
                logger.info("User registered successfully.")
                return redirect("listing-list")
            
            messages.error("Korisnik sa ovom imejl adresom već postoji. Pokušaj ponovo.")

            # 5 Security logging
            logger.error("Registration failed because an user with the email address already exists.")
            return render(request, "auth/register.html", {"form": form})            
        
        # 5 Security logging
        logger.error("Registration failed due to validation errors.")
        return render(request, "auth/register.html", {"form": form})
    else:
        form = RegisterForm()

        # 5 Security logging
        logger.info("User 'guest' accessed: Register page.")
        return render(request, "auth/register.html", {"form": form})

For some unknown reason, I get error on form.is_valid() saying that a NoneType object is not callable, but the form is not None. The form has custom function-based validators named alpha and adult.

class RegisterForm(UserCreationForm):
    class Meta:
        model = CustomUser
        fields = ["email", "password1", "password2", "phone", "first_name", "last_name", "birth_date"]
        # 2 Input validation & sanitization
        error_messages = {
            "email": {"required": _("email.required")},
            "phone": {"required": _("phone.required")},
            "first_name": {"required": _("first_name.required")},
            "last_name": {"required": _("last_name.required")},
            "birth_date": {"required": _("birth_date.required")},
        }
        widgets = {"birth_date": forms.DateInput(attrs={"type": "date"})}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 3 Input validation & sanitization
        self.fields["password1"].error_messages = {"required": _("password1.required")}
        self.fields["password2"].error_messages = {"required": _("password2.required")}
        self.fields["email"].validators = [EmailValidator(message=_("email.email"))]
        self.fields["phone"].validators = [RegexValidator(regex="^\+381 \d{2} \d{6,7}$", message=_("phone.regex"))]
        self.fields["first_name"].validators = [alpha(value=self.data.get("first_name"), field="first_name")]
        self.fields["last_name"].validators = [alpha(value=self.data.get("last_name"), field="last_name")]
        self.fields["birth_date"].validators = [adult]

        for field in self.fields:
            self.fields[field].widget.attrs["class"] = "form-control"
        
    # 2 Input validation & sanitization
    def clean_password2(self):
        pass1 = self.cleaned_data["password1"]
        pass2 = self.cleaned_data["password2"]

        if pass1 and pass2 and pass1 != pass2:
            raise forms.ValidationError(_("passowrd2.confirmed"))

        return pass2

How can I fix this error?

EDIT: Added the complete view. The form is already complete, unless you expect the custom validators too.

Please post the complete form, the complete view, and the complete error message with the traceback. (You posted the form twice, I don’t know if that was intentional for some reason.)

Duplicate forms were my oversight.

Maybe. But without seeing the full error message with the traceback, it’s tough to tell what all we need to see.

Here.

Environment:


Request Method: POST
Request URL: http://localhost:8000/registracija/

Django Version: 6.0.1
Python Version: 3.14.2
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'listings',
 'users',
 'auth2']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\core\handlers\base.py", line 198, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\realestate\auth2\views.py", line 85, in register
    return register_post(req) if req.method == "POST" else register_get(req)
           ^^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\realestate\auth2\views.py", line 25, in register_post
    if not form.is_valid():
           ^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\forms.py", line 206, in is_valid
    return self.is_bound and not self.errors
                                 ^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\forms.py", line 201, in errors
    self.full_clean()
    ^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\forms.py", line 337, in full_clean
    self._clean_fields()
    ^^^^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\forms.py", line 345, in _clean_fields
    self.cleaned_data[name] = field._clean_bound_field(bf)
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\fields.py", line 272, in _clean_bound_field
    return self.clean(value)
           ^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\fields.py", line 209, in clean
    self.run_validators(value)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Documents\_Dokumenti\Projekti\_Master\Real Estate Listings App\Secure\Django\venv\Lib\site-packages\django\forms\fields.py", line 194, in run_validators
    v(value)
    ^^^^^^^^

Exception Type: TypeError at /registracija/
Exception Value: 'NoneType' object is not callable

This error is precisely in the code that is attempting to run a validator on a field. So yes, we would need to see the complete form, including the code for the alpha and adult validators.

The validators.

def alpha(value, field):
    if value and value != "" and not str(value).isalpha():
        raise ValidationError(_(f"{field}.alpha"))
    
def adult(value):
    if not isinstance(value, date):
        raise ValidationError( _("birth_date.date"))
      
    today = date.today()
    age = today.year - value.year - ((today.month, today.day) < (value.month, value.day))

    if age < 18:
        raise ValidationError(_("birth_date.adult"))

I believe your alpha validator in improperly defined.

From the docs at Validators:

A validator is a callable that takes a value and raises a ValidationError if it doesn’t meet some criteria.

Your validators are passed 1 parameter, not 2.

If you want a quick test, remove your references to the alpha validator and try again. You should not get this same error. (Or, remove the second parameter and try it.)

I need the field name to embed them in message IDs of the messages in language files.

raise ValidationError(_(f"{field}.alpha"))

The message IDs and message strings. locale\sr\LC_MESSAGES\django.po:

msgid "first_name.alpha"
msgstr "Polje Ime mora sadržati samo slova."

msgid "last_name.alpha"
msgstr "Polje Prezime mora sadržati samo slova."

You might be able to use a validator class to do this.

Take a look at some of the builtin validators to get some ideas: django/django/core/validators.py at stable/6.0.x · django/django · GitHub