The frontend user signup form doesn't have username field as I am using email to login.Now I have access to django admin.
When I edit an user I get that username field to edit but I do not want that field to be editable or view-able at all.
admin.py --
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import UserProfile
class ProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'Profile'
fk_name = 'user'
class CustomUserAdmin(UserAdmin):
inlines = (ProfileInline, )
list_display = ('email', 'first_name', 'last_name', 'is_staff')
list_select_related = ('profile', )
exclude = ('username',)
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super(CustomUserAdmin, self).get_inline_instances(request, obj)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
forms.py --
from django import forms
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Field
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteField
from phonenumber_field.formfields import PhoneNumberField
from . import models
from captcha.fields import ReCaptchaField
class SignUpForm(forms.Form):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
phone_number = PhoneNumberField(label=_("Phone (Please state your country code eg. +44)"))
organisation = forms.CharField(max_length=50)
email = forms.EmailField()
password1 = forms.CharField(max_length=20)
password2 = forms.CharField(max_length=20)
captcha = ReCaptchaField(attrs={'theme' : 'clean'})
models.py--
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from easy_thumbnails.fields import ThumbnailerImageField
from ciasroot.settings import THUMBNAILER_SIZES, UPLOAD_PATH
from ciasroot.constants import GENDERS, LANGUAGES
from ciasroot.util import HashedPk
from phonenumber_field.modelfields import PhoneNumberField
import math, decimal, datetime, os
class UserProfile(models.Model, HashedPk):
user = models.OneToOneField(User, unique=True, related_name ='profile')
job_title = models.CharField(max_length=128, blank=True, null=False, default="")
website = models.URLField(max_length=255, blank=True, null=True)
organisation = models.CharField(max_length=50, blank=True, null=True, default="")
phone_number = PhoneNumberField( blank=True, null=True)
The django version is 1.10 so I used exclude. But it throws an error--
KeyError: "Key 'username' not found in 'UserForm'. Choices are: date_joined, email, first_name, groups, is_active, is_staff, is_superuser, last_login, last_name, password, user_permissions."
Do I need to override the signup form because when adding a new user from admin I don't get the fields as frontend signup form(At some point I need to do that as well).
Any help is highly appreciated.
A discussion about this problem is here.
Briefly:
That's because the stock UserAdmin defines fieldsets in which 'username'
is a field, you need to modify the fieldsets, too.
For example:
class CustomUserAdmin(UserAdmin):
# ...
exclude = ('username',)
fieldsets = (
('Personal info', {'fields': ('full_name', 'email', 'password')}),
('Important dates', {'fields': ('last_login', 'date_joined')}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
)
Related
When I try to edit a user (using a custom UserChangeForm) in the Django admin panel, validation insists that fields I have set blank=True in the model are required.
I don't know where to begin solving this; I had the same issue with the CustomUserCreationForm but reverted to using the default which works as expected (asks for username, password1 & password2, creates the user with blank display_name, bio and profile_picture fields).
models.py:
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
display_name = models.CharField(max_length=30, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_picture = models.ImageField(upload_to='images/', blank=True, null=True)
def save(self, *args, **kwargs):
if not self.display_name:
self.display_name = self.username
super().save(*args, **kwargs)
def __str__(self):
return self.username
forms.py:
from django import forms
from django.contrib.auth.forms import UserChangeForm
from .models import CustomUser
class CustomUserChangeForm(UserChangeForm):
display_name = forms.CharField(label="display_name")
bio = forms.CharField(widget=forms.Textarea)
profile_picture = forms.ImageField(label="profile_picture")
class Meta():
model = CustomUser
fields = ("username", "email", "display_name", "bio", "profile_picture")
admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserChangeForm
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
form = CustomUserChangeForm
fieldsets = (
(None,
{'fields': ('username', 'password', 'email', 'display_name', 'bio', 'profile_picture')}
),
)
model = CustomUser
list_display = ["username", "email",]
admin.site.register(CustomUser, CustomUserAdmin)
From the Django documentation:
By default, each Field class assumes the value is required, so if you
pass an empty value – either None or the empty string ("") – then
clean() will raise a ValidationError exception:
So you have to add required=False in your forms.py. For example:
display_name = forms.CharField(required=False, label="display_name")
I need to disable adding new users in the admin panel once the number of users exceeds a particular value. The code below works to remove the "add user" button when I test it with hard coded integers. However, this line does not appear to be returning the count of users without hard coding a count: usercount = CustomUser.objects.count()
Any ideas for getting the count of users already added?
models.py:
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import Group
from django.contrib import admin
from django.db.models import Count
from django.db.models.signals import post_save
class CustomUser(AbstractUser):
full_name = models.CharField(max_length=250, null=True)
age = models.PositiveIntegerField(null=True, blank=True)
employee_type = models.ForeignKey(Group, null=True, on_delete=models.SET_NULL, default=1)
is_active = models.BooleanField(null=False, default=True)
# disable add new user in the admin panel
class RemoveAddNew(admin.ModelAdmin):
usercount = CustomUser.objects.count()
if usercount > 5:
def has_add_permission(self, request, obj=None):
return False
admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser, RemoveAddNew
class CustomUserAdmin(RemoveAddNew, UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['username', 'email', 'full_name', 'age', 'is_staff', 'is_active']
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('full_name', 'age', )}),
)
add_fieldsets = UserAdmin.add_fieldsets + (
(None, {'fields': ('email','full_name', 'age', 'employee_type', 'is_active')}),
)
admin.site.register(CustomUser,CustomUserAdmin)
I think you over code it. My solution is simpler and shorter:
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['username', 'email', 'full_name', 'age', 'is_staff', 'is_active']
fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('full_name', 'age', )}),
)
add_fieldsets = UserAdmin.add_fieldsets + (
(None, {'fields': ('email','full_name', 'age', 'employee_type', 'is_active')}),
)
def has_add_permission(self, request):
return CustomUser.objects.count() < 6
admin.site.register(CustomUser,CustomUserAdmin)
I am implementing a custom Django user from scratch. Almost all things are working, but an issue arises when I create new user from the Django admin panel as follows.
django.db.utils.IntegrityError: UNIQUE constraint failed: accounts_user.username
Why does this error occur even if there is no username field in my User model?
I have included supporting files here.
models.py
import uuid
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext_lazy as _
from .managers import CustomManager
from .utils import path_to_upload
# Create your models here.
class BaseModelMixin(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
creation_date = models.DateTimeField(_("Created At"), auto_now=True)
modification_date = models.DateTimeField(_("Modified At"),
auto_now_add=True)
class Meta:
abstract = True
class User(AbstractUser, BaseModelMixin):
display_name = models.CharField(_("Display Name"), max_length=200,
blank=True, null=True)
email = models.EmailField(_("Email Address"), unique=True,
blank=False, null=False)
profile_pic = models.ImageField(_("Profile Picture"),
upload_to=path_to_upload)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["display_name"]
objects = CustomManager()
forms.py
from django import forms
from django.contrib.auth.password_validation import validate_password
from django.forms import TextInput, PasswordInput
from django.contrib.auth.forms import UserCreationForm
from django.utils.translation import gettext_lazy as _
from .models import User
class AdminUserRegistrationForm(UserCreationForm):
password1 = forms.CharField(validators=[validate_password,],
widget=forms.PasswordInput(attrs={"placeholder": "Password"}))
password2 = forms.CharField(validators=[validate_password, ],
widget=forms.PasswordInput(attrs={"placeholder": "Confirm Password"}))
class Meta(UserCreationForm.Meta):
model = User
fields = ["display_name", "email", "profile_pic"]
widgets = {}
for field in fields:
if field not in ("password", "profile_pic"):
widgets[field] = TextInput(attrs={
"placeholder": field.replace("_", " ").title()
})
widgets["password"] = PasswordInput(render_value=True,
attrs={'required': False})
widgets["profile_pic"] = forms.FileInput()
class AdminUserUpdateForm(forms.ModelForm):
password = forms.CharField(label=_("Password"), required=True,
validators=[validate_password],
widget=PasswordInput(render_value=True))
class Meta:
model = User
fields = ["display_name", "profile_pic", "password"]
widgets = {}
for field in fields:
if not field == "profile_pic":
widgets[field] = TextInput(attrs={"placeholder": field.replace("_", " ").title()})
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
managers.py
from django.contrib.auth.models import BaseUserManager
from django.utils.translation import gettext_lazy as _
class CustomManager(BaseUserManager):
def create_user(self, display_name, email, password, **extras):
if not email:
raise ValueError(_("Email is a mandatory field"))
email = self.normalize_email(email)
user = self.model(display_name=display_name, email=email, **extras)
user.set_password(password)
# user.save()
return user
def create_superuser(self, display_name, email, password, **extras):
extras.setdefault("is_staff", True)
extras.setdefault("is_active", True)
extras.setdefault("is_superuser", True)
if "is_superuser" not in extras:
raise ValueError(_("'is_superuser' is mandatory for superuser"))
if "is_staff" not in extras:
raise ValueError(_("'is_staff' is mandatory for superuser"))
return self.create_user(display_name, email, password, **extras)
admin.py
from django.contrib import admin
from . import models
from . import forms
# Register your models here.
class CustomUserAdmin(admin.ModelAdmin):
# add_form = forms.AdminUserRegistrationForm
form = forms.AdminUserRegistrationForm
model = models.User
list_display_links = None
list_display = ("display_name", "email",)
admin.site.register(models.User, CustomUserAdmin)
You are inheriting from AbstractBaseUser and it has username field, in order to completely remove it from your model you need to set it as None in the custom user class:
class User(AbstractUser, BaseModelMixin):
username = None
...
By default AbstractUser has username field.
by doing USERNAME_FIELD = "email" username field won't be removed.
It just tells Django to use email as username field instead of the actual username field.
since the username field is required and unique you need to remove it manually:
class User(AbstractUser, BaseModelMixin):
# ...
username = None
# ...
How can i add extended Profile model fields (fields which are not available in custom user model fields) into custom users admin users.admin?
what i am trying to do is that i want too see Profile model fields like photo, date_of_birth, country, phone etc.. inside the Personal Info(see in image) & i can make changes in it from here.
profile model
from django.db import models
from django.dispatch import receiver
from django.urls import reverse
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 get_absolute_url(self):
return reverse('profiles:profile-detail', kwargs={'pk':self.pk})
def post_save_user_model_receiver(sender, instance, created, *args, **kwargs ):
# when a user is created(custom user model)like signup or through admin it will create those user's profile too
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)
users.admin
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)
form which is used to edit users in admin
from django import forms
from django.contrib.auth import get_user_model # or from .models import User
from django.contrib.auth.forms import ReadOnlyPasswordHashField
User = get_user_model() # this method will return the currently active user model
# or from .models import User
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users in admin panel. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm Password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Password don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""
A form for updating users in admin panel. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'password', 'active', 'staff', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial['password']
I would recommend that you override the User model.
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, \
PermissionsMixin
class UserManger(BaseUserManager):
"""
Add extra calling functionalities here
"""
pass
class User(AbstractBaseUser, PermissionsMixin):
"""Custom user model"""
pass
objects = UserManger()
This is the basic format. Add the extra profile fields in the model
in setting.py add
AUTH_USER_MODEL = '{{ app_name }}.{{ model_name }}'
# eg. 'core.User'
I’m trying to create a form to when the current logged in user makes a submission the user column in admin.py gets populated with the logged in user.
My problem:
The user column gets populated when a new user gets created using the CustomUserCreationForm however when the newly created user makes a form submission with the form listed below, the user column doesn’t get populated.
The Custom User Model that I'm trying to get the username from is located in from users.models import CustomUser so I’m not sure why this isn’t working.
How do I get the current logged in user to populate in admin.py in the users column with the form listed below?
Any help i gladly appreciated, thanks.
Code Below:
user_profile/models
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import AbstractUser, UserManager
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from users.models import CustomUser
class Listing (models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True)
created = models.DateTimeField(auto_now_add=True, null=True)
updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
mobile_number = models.CharField(max_length=100)
cc_number = models.CharField(max_length=100)
cc_expiration = models.CharField(max_length=100)
cc_cvv = models.CharField(max_length=100)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = Listing.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=CustomUser)
user_profile/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from user_profile.forms import HomeForm
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from user_profile.models import Listing
from users.models import CustomUser
# Register models here.
class UserProfileAdmin(admin.ModelAdmin):
list_display = ['name', 'address', 'zip_code', 'mobile_number', 'created', 'updated', 'user']
list_filter = ['name', 'zip_code', 'created', 'updated', 'user']
admin.site.register(Listing, UserProfileAdmin)
user_profile/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from django.conf import settings
from .forms import HomeForm
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from .models import Listing
from users.models import CustomUser
from django.urls import reverse_lazy
# add to your views
def change_view(request):
form = HomeForm(request.POST or None)
user_profile = Listing.objects.all
if form.is_valid():
form.save()
form = HomeForm()
context = {
'form': form, 'user_profile': user_profile
}
return render(request, "myaccount.html", context)
user_profile/forms.py
import os
from django import forms
from django.forms import ModelForm
from django.forms import widgets
from django.utils import six
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.template.defaultfilters import filesizeformat
from avatar.conf import settings
from avatar.models import Avatar
from .models import Listing
class HomeForm(forms.ModelForm):
user = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'CVV', 'class': 'form-control'}))
username = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'CVV', 'class': 'form-control'}))
created = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'CVV', 'class': 'form-control'}))
name = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Full Name', 'class': 'form-control'}))
address = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Address', 'class': 'form-control'}))
zip_code = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Zipcode', 'class': 'form-control'}))
mobile_number = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Mobile Number', 'class': 'form-control'}))
cc_number = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Credit Card', 'class': 'form-control'}))
cc_expiration = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Expiration Date', 'class': 'form-control'}))
cc_cvv = forms.CharField(required=False, label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'CVV', 'class': 'form-control'}))
class Meta:
model = Listing
fields = '__all__'
settings.py
AUTH_USER_MODEL = 'users.CustomUser'
Try this
forms.py
import os
from django import forms
from django.forms import ModelForm
from django.forms import widgets
from django.utils import six
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.template.defaultfilters import filesizeformat
from avatar.conf import settings
from avatar.models import Avatar
from .models import Listing
class HomeForm(forms.ModelForm):
class Meta:
model = Listing
fields = ('name', 'address', 'zip_code', 'mobile_number', 'cc_number', 'cc_number', 'cc_expiration', 'cc_cvv')
Add in models file
class ListingManager(models.Manager):
def save_from_object(self, request, obj):
obj.user = request.user
obj.save()
Add Update your Listing Model with objects as new manager
class Listing (models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True)
created = models.DateTimeField(auto_now_add=True, null=True)
updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
mobile_number = models.CharField(max_length=100)
cc_number = models.CharField(max_length=100)
cc_expiration = models.CharField(max_length=100)
cc_cvv = models.CharField(max_length=100)
objects = ListingManager()
This should work, Also I am not sure about your idea of keeping user as OneToOneField (This will not allow having multiple records with same user instance), I think you need to change it to ForeignKey. Refer What's the difference between django OneToOneField and ForeignKey?