When I started to use Django, I was using FBVs ( Function Based Views ) for pretty much everything including signing up for new users.
But as I delved deep more into projects, I realized that Class-Based Views are usually better for large projects as they are more clean and maintainable but this is not to say that FBVs aren't.
Anyway, I migrated most of my whole project's views to Class-Based Views except for one that was a little confusing, the SignUpView.
In order to make SignUpView in Django, you need to utilize CreateView and SuccessMessageMixin for creating new users as well as displaying a success message that confirms the account was created successfully.
Here's the code :
views.py:
from .forms import UserRegisterForm
from django.views.generic.edit import CreateView
class SignUpView(SuccessMessageMixin, CreateView):
template_name = 'users/register.html'
success_url = reverse_lazy('login')
form_class = UserRegisterForm
success_message = "Your profile was created successfully"
and, the forms.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'first_name']
You can use Django's CreateView for creating a new user object.
# accounts/views.py
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic
class SignUp(generic.CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
For more info, check https://learndjango.com/tutorials/django-signup-tutorial
Related
Hi I am new to Django and I have created a login/logout model Django inbuilt User and UserCreationForm. It is working fine but my issue is I have define two custom inputs in my form and it is displaying on the web page when I run the server but when I check the user under the admin, I only see the details of User defined fields not my custom fields.
How to save it's data to my User model?
or maybe If I defined the custom fields wrong how do I change it so that I can save it's data in my model.
My custom defined fields that is address and phone number is not showing in Admin User and it's data is not getting saved.
model.py
from django.db import models
from django.contrib import auth
# Create your models here.
class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
return "#{}".format(self.username)
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserCreateform(UserCreationForm):
address = forms.CharField(max_length=150, required=True)
phone_number = forms.IntegerField(required=True)
class Meta(UserCreationForm.Meta):
model = get_user_model()
fields = ('username','email','password1','password2')
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = 'Display Name'
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView
from . import forms
# Create your views here.
class SignUp(CreateView):
form_class = forms.UserCreateform
success_url = reverse_lazy('login')
template_name = 'account/signup.html'
Adding fields to a ModelForm doesn't do anything in terms of saving them, if they are not fields of the Model. So of course, address and phone_number aren't saved, your User model doesn't have those fields.
You need to have a Model to save those fields. As explained here, you have two options:
Create a Profile model to save all extra fields
Create a custom User model, subclassing AbstractUser or AbstractBaseUser.
My advice: Do both. Save your extra fields in a Profile model.
And subclass AbstractUser, so you have the option to add useful methods and properties to the User model (right now, just __str__()).
Why not just subclass? Because as your app grows, you'll want to add more an more things to a user's profile. Maybe you want to create different types of profiles, e.g. the private profile and the professional profile. The User itself should be compact, just managing authentication and permissions.
Note: your current User model is wrong. You must not subclass auth.User but auth.AbstractUser.
Well.. I started to create simple app. Following official doc of Django, I created auth logic in separate app with name users, like this:
users/urls.py:
from django.urls import path, re_path, include
from . import views
urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('profile/', views.redirect_to_user_profile, name='redirect-user-profile'),
re_path('profile/(?P<pk>\d+)/', views.UserProfileView.as_view(), name='user-profile'),
path('register/', views.UserRegisterView.as_view(), name='user-register'),
users/views.py:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.views import generic
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
# Create your views here.
def redirect_to_user_profile(request):
url = f'/users/profile/{request.user.id}'
return HttpResponseRedirect(redirect_to=url)
class UserProfileView(generic.DetailView):
model = User
template_name = 'user_profile.html'
class UserRegisterView(generic.CreateView):
form_class = UserCreationForm
template_name = 'register.html'
success_url = '/users/login'
Everything was fine, so I decided to extent basic Django user, to add profile image for example (and more fields later) like this:
users/models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class ProfileUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_image = models.URLField()
#receiver(post_save, sender=User) # Still don't know how, but next rows create ProfileUser when User is created
def create_user_profile(sender, instance, created, **kwargs):
if created:
ProfileUser.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profileuser.save()
def __str__(self):
return f"{self.user}"
Still working fine. Then I decided to add FB login, after some researh I found django-allauth module, following it documentation and add one row in users/urls.py:
path('fb/', include('allauth.urls')),
It also working, But here comes the problem currently I have two separate modules for authorization:
Basic django User auth logic:
And django-allauth auth logic:
How to handle this (best way):
What I think: To use only Django-allauth, but is there a way to extend it with additional ProfileUser, like extend it now with Django User?
Using only Django-allauth is a good assumption.
The way to extend Django User is by something like that:
class ProfileUser(AbstractUser):
profile_image = models.URLField()
REQUIRED_FIELDS = ['email']
class Meta:
managed = True
db_table = 'profile_user'
However, change like that could enforce to make migrations from the beginning. Or trying to fix them manually. This is because of auth app migrations are done as a second just after contenttypes.
Okay, based on #artusiep answer and a lot of research, I found that the best way is to use one of them, but not both at the same time. Also found very good tutorial about both implementation here
I am using a custom user model with an extra field 'uid'. While i am trying to create a new user from the admin page, the uid field is not showing up. I've created a custom user create and update form.please see the code below.
models.py
from django.db import models
# Create your models here.
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
uid = models.CharField(max_length=50)
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
uid = forms.CharField(label = "uid")
class Meta(UserCreationForm):
model = CustomUser
fields = ('username', 'password', 'uid')
def save(self, commit=True):
user = super(UserCreateForm, self).save(commit=False)
user.uid = self.cleaned_data["uid"]
if commit:
user.save()
return user
Did i miss something or am i doing it wrong? please help.
Edit:
admin.py
from django.contrib import admin
from support.models import CustomUser
# Register your models here.
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['username','password','uid']
admin.site.register(CustomUser, CustomUserAdmin)
Don't know if it's the right way, changing the CustomUserAdmin as shown in this answer https://stackoverflow.com/a/45701173/9740712 made the extra field appear.
I got stuck with small issue in django project, I hope I can get some good answers here.
I have added user profile inline form with django User form by doing code like this:
from django.core.exceptions import ValidationError
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.models import User
from djangocalendar.models import UserProfile
from tableapp.models import *
from djangocalendar.models import *
from django import forms
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = True
verbose_name_plural = 'profile'
class MyUserChangeForm(UserChangeForm):
def clean_first_name(self):
if self.cleaned_data["first_name"].strip() == '':
raise ValidationError("First name is required.")
return self.cleaned_data["first_name"]
def clean_last_name(self):
if self.cleaned_data["last_name"].strip() == '':
raise ValidationError("Last name is required.")
return self.cleaned_data["last_name"]
# Define a new User admin
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
inlines = UserProfileInline,
# Register your models here
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Issue I am facing with this, This inline appears with User Add form and with Change user form too. I don't want it to display while adding user.
Like In this screenshot: Inline form appears with add User form! I don't want this to add inline form here. But I want to display inline form while editing user with other forms like personal form, information form.
I have found solution
Define a new User admin
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
inlines = UserProfileInline,
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super(MyUserAdmin, self).get_inline_instances(request, obj)
I have created a functional Django (1.11.5) system which allows me to add numerous Bikes to Manufacturer due to the foreign key capabilities. Unfortunately I can't get my head around how I correctly can redirect user to (PrimaryKey) Manufacturer after the user has updated the Bike information. My views uses Class Based Views for deleting, creating, and updating both the Manufacturer and Bikes.
Below I have displayed both the views.py and URL.py I have within my App.
views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from .models import Manufacturer, Review
class ReviewUpdate(UpdateView):
model = Bike
fields = ['bike_body']
success_url = reverse_lazy('manufacturers:index')
URLs.py
url(r'bike/(?P<pk>[0-9]+)/$',views.BikeUpdate.as_view(), name="bike-update"),
What you can do is override the get_success_url method on your view.
class ReviewUpdate(UpdateView):
model = Bike
fields = ['bike_body']
def get_success_url(self):
return reverse('the-url-you-want', args=(your_key,))
More info about the recently saved object can be found at self.kwargs.