Extending default user using Abstract User - django

I am trying to add some extra fields in default user model. But the new fields is not showing up in admin page. Here are the models of 'users' app.
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
q1 = models.TextField()
q2 = models.TextField()
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreation(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('username', 'email', 'q1', 'q2')
class CustomUserChange(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'q1', 'q2')
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreation, CustomUserChange
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreation
form = CustomUserChange
list_display = ['email', 'username', 'password', 'q1', 'q2']
model = CustomUser
admin.site.register(CustomUser, CustomUserAdmin)
P.S. I have added AUTH_USER_MODEL = users.CustomUser in settings.py

In your admin.py file you need to override UserAdmin as:
class CustomUserAdmin(BaseUserAdmin):
form = CustomUserChange
add_form = CustomUserCreation
list_display = ('email', 'username', 'password', 'q1', 'q2')
fields = ('email', 'username', 'password', 'q1', 'q2')
model = CustomUser
admin.site.register(CustomUser, UserAdmin)
Check this example in the docs for more understanding link

Please check the following things into your django project.
Have you added AUTH_USER_MODEL = 'users.models.CustomUser' to your settings.py file ?
Ensure you have added q1 and q2 to your fields attribute in CustomUserAdmin as follow:
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreation
form = CustomUserChange
list_display = ['email', 'username', 'password', 'q1', 'q2']
fields = ['email', 'username', 'password', 'q1', 'q2']
model = CustomUser

You can just create a user profile model with a OneToOne relation and fire it up using signal whenever a user has been added without having to touch the User model.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
class Profile(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
q1 = models.TextField()
q2 = models.TextField()
def __unicode__(self):
return self.user.q1
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
user_profile = Profile(user=user)
user_profile.save()
post_save.connect(create_profile, sender=User)

Related

Problem adding user's email in Django admin

I created a custom model extending AbstractUser in order to authenticate users by email instad of by username (but not wanting to drop the username, because it will also be used).
This was the first thing I made before running the first migration, everything worked correctly except in the Django admin, when I create a new user, I want these fields to be filled
username
email
password
And the admin only ask me for the username and password. How could I add the email too? Here's my codes
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifier for
authentication instead of username.
"""
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
class User(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User as CustomUser
class CustomUserAdmin(UserAdmin):
model = CustomUser
list_display = ('email', 'is_staff', 'is_active',)
list_filter = ('eamil', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(CustomUser, UserAdmin)
What I have to do? It seems that everything is correct, but the required email field is missing. Notice that this only happens when I use the Add User feature in the admin. When I create a superuser or when I login to the admin, everything is working as expected.
UPDATE:
Here's the content of my forms.py
from django.contrib.auth.forms import UserCreationForm
# the user model was customized it should be invoked
from django.contrib.auth import get_user_model
from django.contrib.auth import forms as auth_forms
from .models import User as CustomUser
class UserChangeForm(auth_forms.UserChangeForm):
class Meta(auth_forms.UserChangeForm.Meta):
model = CustomUser
class UserCreationForm(auth_forms.UserCreationForm):
class Meta(auth_forms.UserCreationForm.Meta):
model = CustomUser
fields = ("username", "email")
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
# the user model was customized it should be invoked
model = get_user_model()
fields = UserCreationForm.Meta.fields + ("email",)
And here the content (updated) of my admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User as CustomUser
from .forms import UserChangeForm, UserCreationForm
class CustomUserAdmin(UserAdmin):
model = CustomUser
list_display = ('email', 'username', 'is_staff', 'is_active',)
list_filter = ('eamil', 'username', 'is_staff', 'is_active',)
form = UserChangeForm
add_form = UserCreationForm
fieldsets = (
(None, {'fields': ('email', 'username', 'password')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'username', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(CustomUser, UserAdmin)
But I still have the same problem, I still can't add an email field in /admin/users/user/add/
The UserAdmin class has the attributes form and add_form which point to form classes to be used to edit and create the user respectively. You need to override these form classes and also set these attributes yourself as these two forms are created for the default user model.
Firstly define these custom forms:
from django.contrib.auth import forms as auth_forms
from .models import User as CustomUser
class UserChangeForm(auth_forms.UserChangeForm):
class Meta(auth_forms.UserChangeForm.Meta):
model = CustomUser
class UserCreationForm(auth_forms.UserCreationForm):
class Meta(auth_forms.UserCreationForm.Meta):
model = CustomUser
fields = ("username", "email")
Next set these in your CustomUserAdmin:
from .forms import UserChangeForm, UserCreationForm
class CustomUserAdmin(UserAdmin):
# Your other attributes here
form = UserChangeForm
add_form = UserCreationForm
In your code, I see
admin.site.register(CustomUser, UserAdmin)
but you have to register through your CustomUserAdmin.
Change your admin.py code to
admin.site.register(CustomUser, CustomUserAdmin)

how to save CustomUser model to another model data

here is my code at users/admin.py,
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from store.models import Customer
from .forms import CustomUserCreationForm, CustomUserChangeForm
CustomUser = get_user_model()
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['email', 'username',]
admin.site.register(CustomUser, CustomUserAdmin)
Also users/forms.py code is,
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = ('email', 'username',)
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = get_user_model()
fields = ('email', 'username',)
I have table on store/models.py ,
class Customer(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, null=True, blank=True,unique=True)
#name = models.CharField(max_length=200, null=True)
email = models.EmailField(max_length=200, null=True)
def __str__(self):
return self.user.username
Now can anyone please suggest me how to create a customer instances in user/admins.py or how to save data to customer table.

Profile model (extending custom user model) not getting registered in django admin

I am new to django and totally confused so what should i do for these..
Note- list_display = ('email', 'first_name',) 'email', 'first_name' which defined in custom user model User
I am not getting errors but it not registering the Profile model
to admin why?
if i am adding phone from Profile model to list_display = ('email', 'first_name', 'phone') i m getting error (admin.E108) The value of 'list_display[2]' refers to 'phone', which is not a callable, an attribute of 'UserAdmin', or an attribute or method on 'users.User'. How can i add phone in list_display?
I uses post_save_user_model_receiver() to auto create profile when
user is created is it best way to do it?
how can i add all Profile model fields for edit/update in users.admin (which is below).
profile model
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.contrib.auth import get_user_model # or from users.models import User
User = get_user_model()
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(null=True, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
phone = models.IntegerField(null=True, blank=True)
country = models.CharField(max_length=150, null=True, blank=True)
city = models.CharField(max_length=150, null=True, blank=True)
bio = models.TextField(max_length=150, null=True, blank=True)
def __str__(self):
return str(self.user.email)
def post_save_user_model_receiver(sender, instance, created, *args, **kwargs ):
if created:
try:
Profile.objects.create(user=instance) # it create those user's profile
except:
pass
post_save.connect(post_save_user_model_receiver, sender=User)
Admin
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth import get_user_model
from .models import Profile
User = get_user_model()
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(BaseUserAdmin):
inlines = (ProfileInline,)
list_display = ('email', 'first_name',)
list_filter = ('admin', 'staff', 'active')
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
users.admin file
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth import get_user_model # or from .models import User
from .forms import UserAdminCreationForm, UserAdminChangeForm
# Register your models here.
User = get_user_model() # or from .models import User
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'first_name', 'get_phone', 'last_login', 'date_joined', 'is_admin')
list_filter = ('admin', 'staff', 'active')
list_select_related = ('profile',)
def get_phone(self, instance): # to show the Phone in list display from the Profile Model
return instance.profile.phone
get_phone.short_description = 'Phone'
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal Info', {'fields': ('first_name', 'last_name',)}),
('Permissions', {'fields': ('admin', 'staff', 'active')}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'first_name', 'last_name', 'password1', 'password2', )
}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
# Remove Group Model from admin. We're not using it.
admin.site.unregister(Group)

Using CustomUser as author giving problem with database?

I am a little stuck, i am using CustomUser in settings (AUTH_USER_MODEL = 'users.CustomUser') and i want to use the username as author in comments.
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
text = models.TextField()
when i run the migrations, it gives me this error
return self.cursor.execute(sql, params) django.db.utils.DataError:
invalid input syntax for integer: "Alandivar"
Alandivar being my superuser username in devmode,
so how can i make it so when a customer put a comment in (requires login), the username is automatically used as author
regards
customuser form
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
from django import forms
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('username', 'email')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
customuser model
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
class CustomUserManager(UserManager):
pass
class CustomUser(AbstractUser):
objects = CustomUserManager()
customuser view
from django.urls import reverse_lazy
from django.views import generic
from .forms import CustomUserCreationForm
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'

User Registeration Using Django Rest Framework

I am trying to create a api for user Registration using the django rest framework.
I have the following models.py file
from __future__ import unicode_literals
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
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE , primary_key = True)
mobileNumber = models.IntegerField(default=0)
avatar= models.ImageField(upload_to = 'User/' , default = '/static/User/defaultProfileImage.png')
def create_user_profile(sender, **kwargs):
if kwargs['created']:
profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_user_profile, sender=User)
This is my Serializers.py file
from rest_framework import serializers
from User.models import UserProfile
from django.contrib.auth.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
username = serializers.CharField()
password1 = serializers.CharField(
style={'input_type': 'password'},
write_only=True)
password2 = serializers.CharField(
style={'input_type': 'password'},
write_only=True)
email = serializers.EmailField()
class Meta:
model = User
fields = (
'id',
'username',
'password1',
'password2',
'email',
'first_name',
'last_name',
)
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = (
'user',
'mobileNumber',
'avatar')
And following is my views.py file
from User.models import UserProfile
from .serializers import UserProfileSerializer
from rest_framework.viewsets import ModelViewSet
class UserProfileViewSet(ModelViewSet):
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
What is the best way to create a User Registeration using the api view that i have created. I tried many alternatives like overriding the create method in the UserProfile Serializer class and also the drf-writable-nested but got errors.
Please suggest me a way out. Also i want that the api is able to register users when called on by an android app.
You can do this in your Serializers.py file, this should work.
class UserSerializer(serializers.HyperlinkedModelSerializer):
mobileNumber = serializers.IntegerField()
avatar= serializers.ImageField()
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password', 'mobileNumber', 'avatar')
def create(self, validated_data):
mobile_number = validated_data.pop('mobileNumber', None)
user = super(UserSerializer, self).create(validated_data)
user.set_password(raw_password=validated_data['password'])
user.save()
userprofile = user.userprofile
userprofile.mobileNumber = mobile_number
userprofile.save()
return user
def update(self, instance, validated_data):
mobile_number = validated_data.pop('mobileNumber', None)
userprofile = instance.userprofile
userprofile.mobileNumber = mobile_number
userprofile.save()
return super(UserSerializer, self).update(instance, validated_data)
Chuck the UserProfileSerializer for this use case, i feel here its not really needed.
Your views.py and models.py look cool to me.
Hope this helps you :-)