Can the User model be overridden to make the email field required? - django

For my application, the email field in the Django User model should be required, but by default it's optional.
I searched this question but most answers I found were talking about making the email field required in the customised UserCreationForm for example:
class CustomUserForm(UserCreationForm):
"""Provide a view for creating users with only the requisite fields."""
class Meta:
model = User
# Note that password is taken care of for us by auth's UserCreationForm.
fields = ('username', 'email')
def __init__(self, *args, **kwargs):
super(CustomUserForm, self).__init__(*args, **kwargs)
self.fields['email'].required = True
but I want to make the email mandatory in the User model as well because I was thinking maybe ModelForm are a frontend thing and the required condition maybe be turned off by the user by using the chrome dev tools, am I wrong? Will making the email required in ModelForm is same as making it required in the user model as well, or can I override the user model to make the email required?

Maybe ModelForm are a frontend thing and the required condition maybe be turned off by the user by using the chrome dev tools, am I wrong?
You are correct that a user can use tools to make an input item not required, in fact you can often alter the DOM and thus alter the HTML form, or even more simply make use of a tool like curl to make a POST request where you can post arbitrary data.
But a Form (and by extent an ModelForm) does not only render the form in HTML, it is also used to validate the data. This thus means that if you use a view with:
def my_view(request):
if request.method == 'POST':
form = CustomUserForm(request.POST, request.FILES)
if form.is_valid():
# …
# …
# …
then the form.is_valid() will return False if the user did not fill in an email address. A form is thus used to validate, clean data, store data in a model, and render a HTML form.

from django.contrib.auth.models import User
from django.db import models
User.add_to_class('email', models.EmailField(blank=False))

in your settings file
AUTH_USER_MODEL = 'yourapp.User'
in your models
from django.db import models
from django.contrib.auth.models import AbstractUser, Permission, Group
from django.utils.translation import gettext_lazy as _
class User(AbstractUser):
groups = models.ManyToManyField(
Group,
verbose_name=_('groups'),
blank=True,
help_text=_(
'The groups this user belongs to. A user will get all permissions '
'granted to each of their groups.'
),
related_name="user_groups",
related_query_name="user",
)
user_permissions = models.ManyToManyField(
Permission,
verbose_name=_('user permissions'),
blank=True,
help_text=_('Specific permissions for this user.'),
related_name="user_permissions",
related_query_name="user",
)
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['email']
# here you can add new fields and attributes
class Meta:
permissions = (
# here you can add pressiion
)
in your admin
from custodia.models import User
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
#admin.register(User)
class UserAdmin(UserAdmin):
list_display = ('email', 'first_name', 'last_name', 'customer', 'is_staff', 'is_active')
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Aditional info'), {'fields': ('your_new_fields',)}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups', 'customer')

Related

User password is not hashed when creating through Django admin panel

I have inherited the user class to make custom authentication. I do not get password hashing this way. It just stores as plain text in MySQL database. I have created staff through admin panel and unable to login as staff. Furthermore I have also created auth API endpoints using DRF and Djoser and am unable to login with the user profiles created through Django admin panel.
Here is my code.
models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
admin.py
from .models import User
class UserAdmin(admin.ModelAdmin):
pass
admin.site.register(User, UserAdmin)
I have seen old replies in Stack Overflow suggesting changing the parent class to django.contrib.auth.admin.UserAdmin . When I try this the add user template form only has 3 fields. Username, Password and Password Confirmation.
admin.py
from django.contrib.auth.admin import UserAdmin as DefaultUserAdmin
from .models import User
class UserAdmin(DefaultUserAdmin):
pass
admin.site.register(User, UserAdmin)
How do I solve this problem.
I wrote a custom UserAdmin as well so i guess i can help you a little bit with that
try this one:
#admin.register(User)
class UserAdmin(UserAdmin):
"""Define admin model for custom User model with no email field."""
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
}),
)
list_display = ('email', 'is_staff')
search_fields = ('email',)
ordering = ('email',)
And i also think that there`s problems in your models.py bcs you dont have userManager
UserManager uses when you`re creating user so i guess problem in that

Adding "group" field in Django User Admin

I am trying to add a "group" field to show group permissions on the user panel in Django 3.1.2. I tried combining this and this, but always end up in either The model User is already registered with 'auth.UserAdmin' or The model User is not registered (when trying to unregister first):
from django.contrib import admin
from django.contrib.auth.models import User
# fails in "model User not registered"
admin.site.unregister(User)
#fails in already registered with auth.UserAdmin
#admin.register(User)
class UserAdmin(admin.ModelAdmin):
def group(self, user):
return ' '.join([g.name for g in user.groups.all()])
list_display = ['username', 'email', 'first_name', 'last_name', 'is_active', group]
list_filter = ['groups', 'is_staff', 'is_superuser', 'is_active']
How would I correctly register my custom UserAdmin?
I don't remeber, where I saw answer on SO, but do like:
admin.site.unregister(User) before.
Than modificate admin.model, as you wish, and then, register again.
from django.contrib.auth.models import User, Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
admin.site.unregister(User)
class GroupInline(admin.StackedInline):
model = Group
#admin.register(User)
class UserAdmin(BaseUserAdmin):
inlines = (GroupInline,)
If you want to show the group a user belong to in the list display:
#admin.register(User)
class UserAdmin(auth_admin.UserAdmin):
def group(self, user):
groups = []
for group in user.groups.all():
groups.append(group.name)
return ' '.join(groups)
group.short_description = 'Group'
and now in your list_display you can have it as this:
list_display = ['username', 'email', 'first_name', 'last_name', 'is_active', 'group']
I hope this works for you

"Please correct the error below" in the Django admin when using custom user models

I am working on a Django app and I followed exactly these instructions to build a custom User.
Now when I try to create a new user from the admin panel, I get this error message
so not very useful. Also I have the same problem whether I use the "change" form or the "create" form.
However if I try to create a new user through the shell, like
MyUser.objects.create_user(email="test#gmail.com", password=None)
it works.
Troubleshooting
Here is the model of the custom user:
class MyUser(AbstractBaseUser):
"""
A base user on the platform. Users are uniquely identified by
email addresses.
"""
email = models.EmailField(
verbose_name = "Email address",
max_length = 100,
unique = True
)
is_active = models.BooleanField(default=True, blank=True)
is_admin = models.BooleanField(default=False, blank=True)
#property
def is_staff(self):
return self.is_admin
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ()
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
'''Does the user have a specific permission?'''
return True
def has_module_perms(self, app_label):
'''Does the user have permissions to view the app `app_label`?'''
return True
One explanation is that it has something to do with a field of MyUser that has blank=False but that is not displayed by my ModelForm. I double checked, and it's fine.
Another explanation would be that the validation of the admin creation form has somehow inherited from the default User model of django.contrib.auth and it is trying to find a field from User that does not exist in MyUser. How can I check that?
Any idea?
I had a similar problem. But it wasn't in the Admin form, it was at the admin list. I was using list_editable fields. When I would save changes, I would get the "Please correct the error below" message with nothing highlighted.
My error was that I had included the first field in the list_display as list_editable. To correct it, I add 'id' to the front of the list_display fields.
Problem
I had a similar problem.
But that's pretty easy to solve.
How to solve it step by step?
First of all we need to talk about overriding, as you said before.
Django by default uses username field in models. And you need to change it like this in your models.py:
USERNAME_FIELD = 'email'
If you still really want to override a lot of code, next: create managers. Something about this: django managers
In your custom manages class you need to override user creation (create_user method) and create_superuser method With this samples:
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
log.debug(f'Creating user: {email}')
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()
log.info('Created user %s', repr(user))
Only after all this steps you can take care about overriding existing forms.
Django doc about this: https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#custom-users-admin-full-example
implementation:
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ('email', )
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('email', )
This forms are used for user Creation in your admin and User changing.
And only now you can add code in your admin.py and change your UserAdmin like that:
#admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('first_name', 'last_name',)}),
('Permissions', {
'fields': ('is_admin',),
}),
('Important dates', {'fields': ('last_login',)}),
)
# 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', 'password1', 'password2', 'is_admin', 'is_root', )}
),
)
list_display = ('email', 'first_name', 'last_name', 'is_admin', 'created_at', 'updated_at',)
list_filter = ('is_admin',)
search_fields = ('email', 'first_name', 'last_name',)
ordering = ('email',)
filter_horizontal = ()
Be sure to add add_fieldsets and to override ordering by email.
In add_fieldsets you need to 2 type of passwords. If there be only 1 - error occures. From your screen by the way.
I hope this helps everyone who ever encounters this problem.
Ok guys, thanks for your answers but my problem actually came from my UserAdmin override.
More specifically, UserAdmin uses add_form and form to refer to the creation and change forms respectively. As I named my variables creation_form and change_form, it did not override the django.contrib.auth.models.User forms and that's why some fields did not validate because my ModelForms were not displaying those User fields.
Now I have renamed creation_form to add_form and change_form to form inside my custom UserAdmin and it works like a charm :-)
I think that this can help, because password CharField in AbstractBaseUser has blank property set default to False:
class MyUser(AbstractBaseUser):
def __init__(self, *args, **kwargs):
super(MyUser, self).__init__(*args, **kwargs)
passwd = [field for field in self._meta.fields if field.attname is 'password']
if passwd:
passwd[0].blank = True

Username still required in custom user model

I am trying to use the new functionality in Django 1.5 to make use of an email address as the username.
Everything is working fine, bar the admin site to update users, which I have had to fiddle with to make passwords not appear raw (and use the password change form etc.) using this code:-
class PlayerChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = Player
class PlayerCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = Player
class PlayerAdmin(auth.admin.UserAdmin):
form = PlayerChangeForm
add_form = PlayerCreationForm
ordering = ['first_name', 'last_name']
list_display = ('primkey', 'email', 'mobile')
list_editable = ('email', 'mobile')
list_filter = ()
fieldsets = ((None, {'fields': ('username', 'first_name', 'last_name', 'email', 'password', 'mobile')}),
('Permissions', {'fields': ('is_active', 'is_admin')}),
('Important dates', {'fields': ('last_login', )}),
)
add_fieldsets = ((None, {
'classes': ('wide',),
'fields': ('username', 'first_name', 'last_name', 'email', 'password1', 'password2')}
),
)
filter_horizontal = ()
def primkey(self, obj):
return ("%s" % (obj.get_full_name()))
primkey.short_description = 'Player'
This makes the admin page look fine but when I actually try and update a Player, it tells me there is an error on the form but doesn't indicate where.
After a bit of messing around, it turns out that it wants the username field to be set (if I add that into the admin form, it says this field is required) but surely this isn't the case as I have set my USERNAME_FIELD to be 'email'?
If I set the field to something, I can then save any changes I've made to the other fields but it doesn't save my update to the username field. But really, I don't want to have to set the username at all - I'm using the email as the username.
Any ideas about this or is this a bug in Django?
The Django Documentation states that the forms must be rewritten:
UserCreationForm
Depends on the User model. Must be re-written for any custom user model.
UserChangeForm
Depends on the User model. Must be re-written for any custom user model.
There is a related ticket: https://code.djangoproject.com/ticket/19353 but the code still expect a username field to be present.

Django 1.5 custom User model error. "Manager isn't available; User has been swapped"

I extend the django user model as described in the dev doc. I wan't to keep most of the original User model features so I extend the AbstractUser class. I've defined in settings.py:
AUTH_USER_MODEL = 'myapp.CustomUser'
My user class:
class CustomUser(AbstractUser):
custom_field = models.ForeignKey('OtherModel')
objects = UserManager()
Everything seems to work fine but when I try to make it managed by the admin site:
admin.site.register(CustomUser, UserAdmin)
I get this error on the admin CustomUser creation page (after validation of the password confirmation form):
AttributeError: Manager isn't available; User has been swapped for 'myapp.CustomUser'
The point is that I need this model managed by the admin site in order to have the same creation process as with the original User model (two step process with password validation).
You need only change form for adding user(overwrite clean_username and change User on get_user_model()
Full working example(If you inherited from AbstractUser)
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class MyUserChangeForm(UserChangeForm):
class Meta:
model = get_user_model()
class MyUserCreationForm(UserCreationForm):
class Meta:
model = get_user_model()
def clean_username(self):
username = self.cleaned_data["username"]
try:
get_user_model().objects.get(username=username)
except get_user_model().DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = (
(None, {'fields': [('username', 'password'),]}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
admin.site.register(MyUser, MyUserAdmin)
I struggled with this error for hours. For me I needed to remove all references to
from django.contrib.auth.models import User
and then replace it with:
from myapp.models import MyUser as User
This is assuming your custom User model is in an app called myapp and you called the model MyUser.
I'm using as User so that I don't have to change where my existing code that makes reference to the the User object from django.contrib.auth.models.
Good luck!
Alan
#aviars
You probably should look at full example in official documentation:
https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example
There are some uncovered questions (permissions handling, for example), but, at least, it's working.
From Django docs:
You should also define a custom manager for your User model.
Subclass AbstractUser already handle objects = UserManager() for you (this code on github at line 327). You don't need to define it in your model again.
I'm not sure why it come with that error. But below config seem work for me with latest Dev version.
Model.py:
class CustomUser(AbstractUser):
custom_field = models.ForeignKey('OtherModel')
# remove : objects = UserManager()
I've found a solution:
I don't use UserAdmin to register the CustomUser in the admin site, I use a custom ModelAdmin.
class CustomUserAdmin(admin.ModelAdmin):
add_form = CustomUserCreationAdminForm
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2')}
),
)
def get_fieldsets(self, request, obj=None):
if not obj:
return self.add_fieldsets
return super(CustomUserAdmin, self).get_fieldsets(request, obj)
def get_form(self, request, obj=None, **kwargs):
defaults = {}
if obj is None:
defaults.update({
'form': self.add_form,
'fields': admin.util.flatten_fieldsets(self.add_fieldsets),
})
defaults.update(kwargs)
return super(CustomUserAdmin, self).get_form(request, obj, **defaults)
Because I want to have a creation form different from the update form, I override the get_form function of the Model Admin as done in the UserAdmin django code. I also have created a custom Creation form for my custom user: CustomUserCreationForm
I received a response in the django-users mailing list that may be better than mine:
Unregister the original User class from the admin site and then register the CustomUser with UserAdmin:
admin.site.unregister(User)
admin.site.register(CustomUser, UserAdmin)
Not tested yet.
EDIT: this last solution doesn't work
Regards
UserAdmin is already registered to manage User, at the end of contrib/auth/admin.py
admin.site.register(User, UserAdmin)
Given you want to register UserAdmin with CustomUser, I think you would first have to unregister the User/UserAdmin pair:
admin.site.unregister(User)
then register your new model. Given the lack of control in the order of module loading, you could create a class derived from UserAdmin and manage your user model with it. This would work everytime, if I'm thinking properly.