# I don't know how to use UserCreationForm

**URL:** <https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646>\
**Category:** Forms & APIs\
**Created:** [August 28, 2022, 1:37am UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646 "2022-08-28T01:37:18Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [August 28, 2022, 1:37am UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/1 "2022-08-28T01:37:18Z")

</div>

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**

```auto
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**

```auto
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**

```auto
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**

```auto
<!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 %}

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 28, 2022, 2:00am UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/2 "2022-08-28T02:00:17Z")

</div>

> [@Sweetbarrow](#):
>
> So I changed it to `UserCreationForm` and it doesn’t work.

What is not working?

- What is happening that you’re not expecting to have happen, or what isn’t happening that you are expecting to see?

Are you getting any error messages in the console where you’re running runserver?

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [August 28, 2022, 2:37am UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/3 "2022-08-28T02:37:53Z")

</div>

There is no error message and it drives me crazy.  
I expected page redirects to “users:list” page when user is registered successfully and so I can see new user in the DB table and Django admin site.  
But what I saw was just turning back to user creation form page.  
I tried to print what happened by overriding `def form_invalid(self, form)` but what was printed was kind of `<TemplateResponse code=200>` thing. (I can’t remember exact message)  
I even tried copy-and-paste code on these Django documentations, but it still not working.

- [Custom users and the built-in auth forms](https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#custom-users-and-the-built-in-auth-forms)
- [Customizing authentication in Django - full example](https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#custom-users-and-the-built-in-auth-forms)

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 28, 2022, 2:49am UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/4 "2022-08-28T02:49:45Z")

</div>

> [@Sweetbarrow](#):
>
> But what I saw was just turning back to user creation form page.

That’s definitely an indication of the submitted form being invalid.

> [@Sweetbarrow](#):
>
> I tried to print what happened by overriding `def form_invalid(self, form)` but what was printed was kind of `<TemplateResponse code=200>` thing. (I can’t remember exact message)

If you’re looking to print out the form errors on the console as a debugging tool, see [Form.errors](https://docs.djangoproject.com/en/4.1/ref/forms/api/#django.forms.Form.errors). That should show you why your submitted form is failing the `is_valid` test.

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [August 28, 2022, 7:19am UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/6 "2022-08-28T07:19:14Z")

</div>

I found the problem.  
I missed `groups` field in the form.  
By the way, I want to limit that `groups` field to specific one like how I wrote in `UserManager`  
Can I do that with `UserCreationForm`?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 28, 2022, 12:01pm UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/7 "2022-08-28T12:01:15Z")

</div>

If you’re talking about assigning the groups field to a specific value, then I wouldn’t do it in the form. I’d do that in the view.

The `groups` field is a many-to-many relationship with Group. This means that adding or removing groups does _not_ change the User object. These are entries added or removed from the ManyToMany join table.  
So if you know (or can determine) what groups are going to be assigned to a user at the time that user is created, I would remove `groups` as a field from the form. I’d process and save the form for that new user, then figure out and assign the groups.

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [August 28, 2022, 12:27pm UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/8 "2022-08-28T12:27:36Z")

</div>

Would you mind if I ask you how to assign group to user from view when user is created?  
As you can see from the `models.py` that I uploaded in this question, I wrote the code to assign users to `Member` group by using `Group.objects.get_or_create(name="Member")` (It’s on line 31)  
But I didn’t know it have no relation with creating user with form and I see the users created with form don’t have group assigned from DB.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [August 28, 2022, 12:29pm UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/9 "2022-08-28T12:29:44Z")

</div>

How do you make _any_ assignment to a many-to-many relationship?

See [Many-to-many relationships | Django documentation | Django](https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_many/)

---

<div class="post-metadata">

**Author:** ![Sweetbarrow](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/sweetbarrow/32/9633_2.png) [@Sweetbarrow](https://forum.djangoproject.com/u/Sweetbarrow)\
**Post date:** [August 28, 2022, 12:59pm UTC](https://forum.djangoproject.com/t/i-dont-know-how-to-use-usercreationform/15646/10 "2022-08-28T12:59:31Z")

</div>

Wow, Thanks.  
I wrote the code below and it worked.

```auto
class UserCreateView(CreateView):
...
    def form_valid(self, form):
        if form.is_valid:
            self.object = form.save()
            member_group = Group.objects.get(name="Member")
            self.object.groups.set([member_group])
            return super().form_valid(form)
...

```
