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 %}