简体   繁体   中英

How to extend django UserCreationForm model to include phone number field

I cant seem to find any posts here regarding extending the Django UserCreationForm model to include a phone number field for users to enter their number and then validate the phone number using phonenumbers.parse in the backend to check if the number is in the respective format and whether it exists or not. I need to know what code I should include in my forms.py under my "users" app.

I've tried including normal html text field for the phonenumbers and it does not belong to the default UserCreationForm model in Django and neither can it be stored in the database. (I need it to be stored in the database for the phone numbers). I am only using forms.py, views.py and register.html to be rendered in views as shown below, currently I am not using models.py.

/* forms.py */ 

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
# from validate_email import validate_email


class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()
    phone_number = forms.IntegerField(required=True)

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']

        def save(self, commit=True):
            user = super(UserCreationForm, self).save(commit=False)
            user.email = self.cleaned_data['email']

            if commit:
                user.save()

            return user

/* views.py */
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm


def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f'Account created for {username}!')
            return redirect('blog-home')
    else:
        form = UserRegisterForm()
    return render(request, 'users/register.html', {'form': form})

/* register.html */
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
    <div class="content-section">
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Join Today</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Sign 
Up</button>
            </div>
        </form>
        <div class="border-top pt-3">
            <small class="text-muted">
                ALready Have An Account? <a class="ml-2" href="#">Sign In</a>
            </small>
        </div>
    </div>
{% endblock content %}

I need to include a phone number field as part of the UserCreationForm in django and validate the number to check if it exists or not and then save the number in the database.

I usually extend Django User Model using OneToOneLink

models.py

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone = models.CharField(max_length=11, blank=True) #  change the field to watever works for you


#  This will auto create a profile of user with blank phone number that can be updated later.
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

forms.py

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ('phone')

views.py

def create_user(request):
    if request.method == 'POST':
        user_form = UserForm(request.POST, instance=request.user)
        profile_form = ProfileForm(request.POST, instance=request.user.user_profle)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, _('New user created successfully'))
            return redirect('settings:profile')
        else:
            messages.error(request, _('Please correct the error below.'))
    else:
        user_form = UserForm(instance=request.user)
        profile_form = ProfileForm(instance=request.user.user_profile)
    return render(request, 'template_name.html', {
        'user_form': user_form,
        'profile_form': profile_form
    })

template:

<form method="post">
  {% csrf_token %}
  {{ user_form.as_p }}
  {{ profile_form.as_p }}
  <button type="submit">Save changes</button>
</form>

I've been struggling with this issue also. I've found a solution that works ok, but may have some pitfalls, which it would be good to get views on. My solution is a combination of the other answer to this question, with two modifications. Firstly the code above should be used to update a user rather than create one, because at registration no user profile exists so can't be called. Secondly, I removed the create_user_profile method on the model and used the answer posted here How to Extend UserCreateForm to save the extended user information at registration. The reason for removing the create_user_profile was to prevent interference with the save() method on the form. The extended model i'm using is called Account.

I also found this article useful extending the django user model , and I'm still considering whether one of the other options might be more appropriate.

My code looks like this:

Views:

def register_view(request):
    form = AccountRegisterForm(request.POST or None)
    if form.is_valid():
        form.save()
        return redirect("accounts:login")
    context = {"form": form}
    return render(request, "accounts/register.html", context)

def user_update_view(request):
    user_obj = User.objects.get(username=request.user)
    account_obj = Account.objects.get(user=request.user)
    user_form = UserForm(request.POST or None, instance=user_obj)
    account_form = AccountForm(request.POST or None, instance=account_obj)
    if user_form.is_valid() and account_form.is_valid():
        user_form.save()
        account_form.save()
        return redirect(reverse("accounts:detail"))
    context = {
        "account_form": account_form,
        "user_form": user_form,
    }
    return render(request, "accounts/account_update.html", context)

Forms

class AccountRegisterForm(UserCreationForm):
    group = forms.ModelChoiceField(queryset=Group.objects)
    dir = forms.ModelChoiceField(queryset=Directorate.objects)

    class Meta:
        model = User
        fields = (
            "username",
            "first_name",
            "last_name",
            "group",
            "dir",
        )

 

    def save(self, commit=True):
        if not commit:
            raise NotImplementedError(
                "Can't create User and UserProfile without database save"
            )
        user = super(AccountRegisterForm, self).save(commit=True)
        user_account = Account(
            user=user,
            group=self.cleaned_data["group"],
            dir=self.cleaned_data["dir"],
        )
        user_account.save()


class UserForm(forms.ModelForm):

    class Meta:
        model = User
        fields = ("username", "first_name", "last_name")

       


class AccountForm(forms.ModelForm):

    class Meta:
        model = Account
        fields = (
            "group",
            "dir",
        )

       

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM