Reputation: 239
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.
Upvotes: 2
Views: 2924
Reputation: 69
UPDATE to initial answer. I decided while the solution below worked it was preferable to inherit the AbstractUser
model and add my own requirements in my own bespoke user model. Once in place it's far more straight forward dealing with views and templates. I hesitated at first as I didn't feel confident enough to mess around with the default User model, but it is actually very simple. It also helped me understand abstracting models in general via.
class Meta:
abstract = True
The posts here were very helpful.
Previous post:
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)
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",
)
Upvotes: 0
Reputation: 110
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>
Upvotes: 0