I want to make user registration form by using UserCreationForm and CreateView but I don’t know how to do it.
It works fine with ModelForm and CreateView but when I did that, I didn’t know existence of UserCreationForm.
So I changed it to UserCreationForm and it doesn’t work.
I don’t know how to solve it and I can’t find readable document related to UserCreationForm.
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import Group
from django.forms import ModelChoiceField
from branches.models import Branch
from users.models import User
class UserForm(UserCreationForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user")
super(UserForm, self).__init__(*args, **kwargs)
self.fields["password1"].widget.attrs["class"] = "form-control"
self.fields["password2"].widget.attrs["class"] = "form-control"
if self.user.is_superuser:
self.fields["branch"] = ModelChoiceField(
queryset=Branch.objects.all(),
required=True,
label="지점",
widget=forms.Select(
attrs={
"class": "form-select",
},
),
)
self.fields["groups"] = ModelChoiceField(
queryset=Group.objects.all(),
required=True,
label="그룹",
widget=forms.Select(
attrs={
"class": "form-select",
},
),
)
else:
self.fields["branch"] = ModelChoiceField(
queryset=Branch.objects.filter(branch=self.user.branch),
required=True,
label="지점",
widget=forms.Select(
attrs={
"class": "form-select",
}
),
)
self.fields["groups"] = ModelChoiceField(
queryset=Group.objects.filter(name__in=["회원", "직원"]),
required=True,
label="그룹",
widget=forms.Select(
attrs={
"class": "form-select",
},
),
)
def clean_phone(self):
phone_number = self.cleaned_data["phone"]
phone_number = phone_number.replace("-", "")
if len(phone_number) == 0:
return phone_number
elif phone_number[0:2] == "02" and len(phone_number) == 9:
phone_number = [phone_number[0:2], phone_number[2:5], phone_number[5:]]
phone_number = "-".join(phone_number)
elif phone_number[0:2] == "02" and len(phone_number) == 10:
phone_number = [phone_number[0:2], phone_number[2:6], phone_number[6:]]
phone_number = "-".join(phone_number)
elif phone_number[0] != 0 and len(phone_number) == 8:
phone_number = [phone_number[0:4], phone_number[4:]]
phone_number = "-".join(phone_number)
elif len(phone_number) == 10:
phone_number = [phone_number[0:3], phone_number[3:6], phone_number[6:]]
phone_number = "-".join(phone_number)
elif len(phone_number) == 11:
phone_number = [phone_number[0:3], phone_number[3:7], phone_number[7:]]
phone_number = "-".join(phone_number)
return phone_number
class Meta:
model = User
fields = (
"username",
"full_name",
"groups",
"birthday",
"gender",
"phone",
"branch",
"license_type",
"plan_type",
)
widgets = {
"username": forms.TextInput(
attrs={
"class": "form-control",
}
),
"full_name": forms.TextInput(
attrs={
"class": "form-control",
}
),
"birthday": forms.DateInput(
attrs={
"type": "date",
"class": "form-control",
}
),
"gender": forms.RadioSelect(
attrs={
"class": "form-check-input",
},
),
"phone": forms.TextInput(
attrs={
"type": "tel",
"class": "form-control",
},
),
"license_type": forms.Select(
attrs={
"class": "form-select",
},
),
"plan_type": forms.Select(
attrs={
"class": "form-select",
},
),
"staff": forms.RadioSelect(
choices=[(True, "예"), (False, "아니오")],
attrs={
"class": "form-check-input",
},
),
}
models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, Group
from django.core.validators import RegexValidator
from django.db import models
from django.urls import reverse
from django.utils import timezone
from branches.models import Branch
# Create your models here.
phone_validator = RegexValidator(
regex="\d{2,4}-?\d{3,4}(-?\d{4})?",
message="This is not valid phone number format.",
)
class UserManager(BaseUserManager):
def create_user(
self,
username,
full_name,
birthday,
gender,
phone,
branch,
password=None,
**kwargs,
):
user = self.model(
username=username,
full_name=full_name,
group=Group.objects.get_or_create(name="Member"),
birthday=birthday,
gender=gender,
phone=phone,
license_type=kwargs["license_type"],
plan_type=kwargs["plan_type"],
branch=Branch.objects.get(srl=branch),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_staff(
self, username, full_name, birthday, gender, phone, branch, password, **kwargs
):
user = self.create_user(
username, full_name, birthday, gender, phone, branch, password, kwargs
)
user.staff = True
user.group = (Group.objects.get_or_create(name="Staff"),)
user.save(using=self._db)
return user
def create_superuser(
self, username, full_name, birthday, gender, phone, branch, password, **kwargs
):
user = self.create_user(
username, full_name, birthday, gender, phone, branch, password, kwargs
)
user.staff = True
user.superuser = True
user.group = (Group.objects.get_or_create(name="Superuser"),)
user.save(using=self._db)
return user
class User(AbstractBaseUser):
objects = UserManager()
GENDERS = (
(None, "Not chosen"),
("M", "Male"),
("F", "Female"),
)
LICENSE_TYPES = (
(None, "Not chosen"),
("1L", "Class 1 Large"),
("1O", "Class 1 Ordinary"),
("1OA", "Class 1 Ordinary (Automatic)"),
("2O", "Class 2 Ordinary"),
("2OA", "Class 2 Ordinary (Automatic)"),
("P", "Practice"),
)
PLAN_TYPES = (
(None, "Not chosen"),
("T", "Time-based"),
("G", "Guarantee"),
("P", "Practice"),
)
srl = models.BigAutoField(
primary_key=True,
verbose_name="Serial",
)
username = models.TextField(
unique=True,
verbose_name="Username",
)
full_name = models.TextField(
verbose_name="Full name",
)
password = models.TextField(
verbose_name="Password",
)
groups = models.ManyToManyField(
to=Group,
verbose_name="Groups",
)
birthday = models.DateField(
verbose_name="Date of birth",
)
gender = models.TextField(
verbose_name="Gender",
choices=GENDERS,
)
phone = models.TextField(
verbose_name="Phone number",
validators=(phone_validator,),
)
branch = models.ForeignKey(
"branches.Branch",
verbose_name="Branch",
on_delete=models.DO_NOTHING,
)
license_type = models.CharField(
max_length=3,
verbose_name="License type",
choices=LICENSE_TYPES,
blank=True,
null=True,
default=None,
)
plan_type = models.CharField(
max_length=1,
verbose_name="Plan type",
choices=PLAN_TYPES,
blank=True,
null=True,
default=None,
)
staff = models.BooleanField(
verbose_name="Is staff",
default=False,
)
active = models.BooleanField(
verbose_name="Is active",
default=True,
)
superuser = models.BooleanField(
verbose_name="Is active",
default=False,
)
last_login = models.DateTimeField(
verbose_name="Last login",
default=timezone.now,
)
date_joined = models.DateTimeField(
verbose_name="Date joined",
default=timezone.now,
)
USERNAME_FIELD = "username"
REQUIRED_FIELDS = (
"name",
"birthday",
"gender",
"phone",
"branch",
)
@property
def is_staff(self):
return self.staff
@property
def is_active(self):
return self.active
@property
def is_superuser(self):
return self.superuser
def has_perm(self, perm, obj=None):
return self.staff
def has_module_perms(self, app_label):
return self.staff
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
ordering = [
"branch",
"srl",
]
def __str__(self):
if self.gender == "M":
gender_short = "M"
elif self.gender == "F":
gender_short = "F"
return f"{self.full_name} ({self.branch}/{self.birthday.strftime('%y%m%d')}/{gender_short})"
def get_absolute_url(self):
return reverse("users:detail", kwargs={"srl": self.srl})
views.py
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView
from users.forms import UserForm
from users.models import User
# Create your views here.
class UserCreateView(CreateView):
model = User
form_class = UserForm
success_url = reverse_lazy("users:list")
def get_form_kwargs(self):
kwargs = super(UserCreateView, self).get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["page_title"] = "Add user"
return context
Template
<!DOCTYPE html>
{% extends "main/base.html" %}
{% load static %}
{% block content %}
<form action="" method="POST" class="container d-grid gap-3 justify-content-evenly align-items-center">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.username.id_for_label }}">{{ form.username.label }}</label>
<div class="col">{{ form.username }}</div>
{{ form.username.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.full_name.id_for_label }}">{{ form.full_name.label }}</label>
<div class="col">{{ form.full_name }}</div>
{{ form.full_name.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.password1.id_for_label }}">{{ form.password1.label }}</label>
<div class="col">{{ form.password1 }}</div>
{{ form.password1.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.password2.id_for_label }}">{{ form.password2.label }}</label>
<div class="col">{{ form.password2 }}</div>
{{ form.password2.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.birthday.id_for_label }}">{{ form.birthday.label }}</label>
<div class="col">{{ form.birthday }}</div>
{{ form.birthday.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.gender.id_for_label }}">{{ form.gender.label }}</label>
<div class="col">
{% for choice in form.gender %}
<div class="form-check">
{{ choice.tag }}
<label class="form-check-label" for="{{ choice.id_for_label }}">{{ choice.choice_label }}</label>
</div>
{% endfor %}
</div>
{{ form.gender.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.phone.id_for_label }}">{{ form.phone.label }}</label>
<div class="col">{{ form.phone }}</div>
{{ form.phone.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.branch.id_for_label }}">{{ form.branch.label }}</label>
<div class="col">{{ form.branch }}</div>
{{ form.branch.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.license_type.id_for_label }}">{{ form.license_type.label }}</label>
<div class="col">
{{ form.license_type }}
</div>
{{ form.license_type.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.plan_type.id_for_label }}">{{ form.plan_type.label }}</label>
<div class="col">
{{ form.plan_type }}
</div>
{{ form.plan_type.errors }}
</div>
<div class="row">
<label class="col-4 col-form-label text-nowrap" for="{{ form.staff.id_for_label }}">{{ form.staff.label }}</label>
<div class="col">
{% for choice in form.staff %}
<div class="form-check">
{{ choice.tag }}
<label class="form-check-label" for="{{ choice.id_for_label }}">{{ choice.choice_label }}</label>
</div>
{% endfor %}
</div>
{{ form.staff.errors }}
</div>
<div class="row">
<div class="col d-flex justify-content-end">
<button class="btn btn-primary" type="submit">Save</button>
</div>
</div>
</form>
{% endblock %}