Search code examples
pythonpython-3.xdjangodjango-modelsdjango-views

How do I create a custom RegistrationForm using django-registration in Django 5.0.2 with Django Registration 3.4


I admit I'm new to Django but I've been banging my head against the wall with this problem all day. I've created a new application and inherited classes from django_registration, but it seems my form data is never saved. My fields show up and are accessible on the front end as well as the administration area, but user registration never seems to happen and I don't get an error. (It is working fine with standard django-registration but I want to expand it and plan for the future.)

forms.py

from django_registration.forms import RegistrationForm
from authentication.models import MyCustomUser
from django import forms

class MyCustomUserForm(RegistrationForm): 
    class Meta(RegistrationForm.Meta):
        model = MyCustomUser
        #fields = "__all__"
        fields = ['username', 'email', 'first_name', 'last_name', 'profile_photo', 'password1', 'password2']

models.py

from django.contrib.auth.models import AbstractUser
from django.db import models
from django import forms

class MyCustomUser(AbstractUser):
    ROLE_CHOICES = (
        ('APPLICANT', 'Applicant'),
        ('EMPLOYEE', 'Employee'),
        ('ADMIN', 'Admin'),
        (None, 'None')
    )
    role = models.CharField(max_length=30, choices=ROLE_CHOICES)
    profile_photo = models.ImageField()
    #username = forms.CharField(max_length = 100) #this is already handled for us in AbstractUser
    #email  = forms.EmailField(max_length = 100) #this is already handled for us in AbstractUser
    #password1 = forms.CharField(widget = forms.PasswordInput(), max_length = 100) #this is already handled for us in AbstractUser
    #password2 = forms.CharField(widget = forms.PasswordInput(),  max_length = 100) #this is already handled for us in AbstractUser
    first = forms.CharField(max_length = 100 )
    last = forms.CharField(max_length = 100)
    #USERNAME_FIELD = username #this is already handled for us in AbstractUser
    REQUIRED_FIELDS = []

admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import MyCustomUserForm
from .models import MyCustomUser

class CustomUserAdmin(UserAdmin):
    add_form = MyCustomUserForm
    #form = CustomUserChangeForm
    model = MyCustomUser
    list_display = ["email", "username", "first_name", "last_name", "profile_photo", "role"]

admin.site.register(MyCustomUser, CustomUserAdmin)

settings.py

AUTH_USER_MODEL = 'authentication.MyCustomUser'

urls.py

path('accounts/register/', SignUpView.as_view(), name='django_registration_register')

views.py

from django.shortcuts import render, redirect
from django.views.generic import View
from django.views import generic
from django_registration.views import RegistrationView as BaseRegistrationView
from authentication.forms import MyCustomUserForm

class SignUpView(BaseRegistrationView):#generic.CreateView
    form_class = MyCustomUserForm
    template_name = "authentication/registration_form.html"

I tried adding methods from https://github.com/ubernostrum/django-registration/blob/trunk/src/django_registration/backends/activation/views.py into my views.py but there is no difference. I thought if I inherited the class the methods would be accessible anyway. I've scoured the documentation at https://django-registration.readthedocs.io/en/latest/index.html trying to figure out what I need to do but it's not clear to me what I'm missing here.


Solution

  • Your MyCustomUser model inherits from AbstractUser, which is correct but the usage of Django forms fields directly in your model (first and last variable) is not correct. Models should define database fields, not form fields. You should remove those and use the first_name and last_name fields provided by AbstractUser like below:

    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    class MyCustomUser(AbstractUser):
        ROLE_CHOICES = (
            ('APPLICANT', 'Applicant'),
            ('EMPLOYEE', 'Employee'),
            ('ADMIN', 'Admin'),
            (None, 'None')
        )
        role = models.CharField(max_length=30, choices=ROLE_CHOICES, default=None, blank=True, null=True)
        profile_photo = models.ImageField(upload_to='profile_photos/', blank=True, null=True)  # Specify upload directory and make it optional if you want
    

    This should fix your issue.