Modifing fields form order of CustomUser model - python

I created a customUser model so that the default User is overwritten.
This is my customUser model:
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
from crispy_forms.helper import FormHelper
class CustomUserCreationForm(UserCreationForm):
helper = FormHelper()
class Meta(UserCreationForm):
model = CustomUser
fields = ('first_name', 'username', 'email', 'last_name', 'organization', 'location', 'postcode', 'phone', 'agree_conditions')
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm):
model = CustomUser
fields = ('username', 'email', 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')
Everything works perfectly however I am not able to change the order of the "User default" fields.
I know how to re-order the form fields, I can simply change the order in the fields = (a, b, c). For example if I want "c" to appear before "a" and "b" in the form, I can do: fields = (c, a, b).
HOWVER I want to move up the password and password confirmation
but I do not know how to do so because I do know know their name in the User default model.
Ideally I want this:
fields = ('username', 'email', 'PASSWORD_WHICH_I_DONT_KNOW_THE_NAME', 'CONFIRMPASSWORD_WHICH_I_DONT_KNOW_THE_NAME' 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')

Solved, it was silly of me.
I inspected the HTML of the form and found out that:
the "PASSWORD_WHICH_I_DONT_KNOW_THE_NAME" is named by default: password1
The "CONFIRMPASSWORD_WHICH_I_DONT_KNOW_THE_NAME" is named by default: password2
So it will be:
fields = ('username', 'email', 'password1', 'password2' 'first_name', 'last_name','organization', 'location', 'postcode', 'phone', 'agree_conditions')

Related

Django Admin restrict users to be added to more than one group

I am creating a customised Django Admin and I want to restrict users to be associated to no more than one group. I am using Django 4.1 and Python 3.11
admin.py:
from django.contrib import admin
from typing import Set
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.utils.translation import gettext_lazy as _
from .models import User
#admin.register(User)
class UserAdmin(DjangoUserAdmin):
ordering = ('is_staff', 'is_active', 'email', 'organisation')
list_display = ('email', 'name', 'organisation', 'is_staff', 'is_active', 'is_superuser', 'date_joined')
fieldsets = (
("Personal info", {'fields': ('name', 'email', 'password', 'organisation')}),
("Permissions", {'fields': (
# 'is_active',
# 'is_staff',
# 'is_superuser',
'groups',
# 'user_permissions'
)}))
add_fieldsets = (
(None, {'classes': ('wide',), 'fields': ('name', 'email', 'password1', 'password2', 'organisation')}),
)
Is there a way to change this in the admin code?
Or it is possible to disable the group widget ("Choose all") on the page? if so which html page is used for groups?
Yes, it is possible to restrict the number of groups a user can be associated with in Django. One way to do this is to override the save_model() method in your custom UserAdmin class and perform the check there, so:
#admin.register(User)
class UserAdmin(DjangoUserAdmin):
# ... other stuff
# ... other stuff
def save_model(self, request, obj, form, change):
if obj.groups.count() > 1:
self.message_user(request, _('Users can only be associated with one group.'), level=messages.ERROR)
else:
super().save_model(request, obj, form, change)

Get users goup name DRF

I'm trying to show user group name instead of it's id .
I have this serilizer class for user class and I used this User = auth.get_user_model() for user Model
but it show NULL instead of theier name .. when i delete get_groups function i will see related groups id why ?
what is correct way to get all users group?
class UserSerializer(ModelSerializer):
groups = SerializerMethodField()
def get_groups(self, obj):
return obj.groups.name
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'date_joined',
'last_login',
'is_staff',
'is_superuser',
'is_active',
'groups'
]
try it
groups = serializers.SlugRelatedField(many=True, read_only=True, slug_field="name")
Try this,
class UserSerializer(ModelSerializer):
def get_groups(self, obj):
return obj.groups.values_list('name', flat=True)
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'date_joined',
'last_login',
'is_staff',
'is_superuser',
'is_active',
'groups'
]
This would return all grups related to paricular user as list
Example:
In [5]: user =User.objects.get(id=1)
In [6]: user.groups.values_list('name',flat=True)
Out[6]: ['grp_name_1', 'grp_name_2']
In [8]: user.groups.all()
Out[8]: [<Group: grp_name_1>, <Group: grp_name_2>]

Extendings Django's UserCreationForm

I'm trying to extend Django's django.contrib.auth.forms.UserCreationForm to include email and name fields. My similar extension of the UserChangeForm works fine, but UserCreationForm still only shows the default username, password1, and password2 fields. Any ideas what I'm doing wrong?
forms.py
class AuthorCreation(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2',
'first_name', 'last_name', 'email', 'groups', 'is_staff')
class AuthorChange(UserChangeForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name',
'email', 'password', 'groups', 'is_staff')
admin.py
class AuthorAdmin(UserAdmin):
"""Admin class for creating and managing Authors"""
inlines = [AuthorInline]
fieldsets = (
(None, {
'fields': ('username', ('first_name', 'last_name'),
'email', 'password', 'groups', 'is_staff')
}),
)
class Media:
css = {
'all': [
'css/codenotes-admin.css',
]
}
def get_form(self, request, obj=None, **kwargs):
if obj is None:
return forms.AuthorCreation
else:
return forms.AuthorChange
admin.site.unregister(User)
admin.site.register(User, AuthorAdmin)
Again, the AuthorChangeForm correctly displays all the fields, but AuthorCreationForm only displays the username, password1, and password2 fields (plus the inline forms, which works fine on both).
I assume the problem is with the fieldsets, but I can't figure it out from the docs.
I figured out the solution. The problem was, as I suspected, the fieldsets. It turns out that the UserAdmin class inherits has TWO fieldsets that need to be overridden, fieldsets and add_fieldsets. I didn't see this mentioned anywhere in the docs (maybe I just missed it); I had to dig through the source to find it. As the name suggests, add_fieldsets is used when adding a new user. The following admin class works as expected:
admin.py
class AuthorAdmin(UserAdmin):
"""Admin class for creating and managing Authors"""
inlines = [AuthorInline]
fieldsets = (
(None, {
'fields': ('username', ('first_name', 'last_name'),
'email', 'password', 'groups', 'is_staff')
}),
)
add_fieldsets = (
(None, {
'fields': ('username', 'password1', 'password2',
('first_name', 'last_name'),
'email', 'groups', 'is_staff'),
}),
)
class Media:
css = {
'all': [
'css/codenotes-admin.css',
]
}
def get_form(self, request, obj=None, **kwargs):
if obj is None:
return forms.AuthorCreation
else:
return forms.AuthorChange
admin.site.unregister(User)
admin.site.register(User, AuthorAdmin)
From the Django doc:
class UserCreationForm¶ A ModelForm for creating a new user.
It has three fields: username (from the user model), password1, and
password2. It verifies that password1 and password2 match, validates
the password using validate_password(), and sets the user’s password
using set_password().
So it seems you have to create the extra fields yourself like this:
class AuthorCreation(UserCreationForm):
first_name = forms.CharField(required=True, label="First Name")
... etc ...
class Meta:
model = User
fields = ('username', 'password1', 'password2',
'first_name', 'last_name', 'email', 'groups', 'is_staff')

Django Rest Framework Serialization error in ListAPIView

I am getting below error
Error -- 'many' is an invalid keyword argument for this function"
In ListAPIView while serializing a object.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'uuid', 'email', 'password', 'first_name', 'last_name', 'mobile_no', 'dob', 'username',)
class CorporateProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(many=True)
class Meta:
model = CorporateProfile
fields = ('user', 'id', 'uuid', 'company_name', 'company_type',)
views.py
class CorporateListView(ListAPIView):
serializer_class = CorporateProfile
queryset = CorporateProfile.objects.all()
What am i doing wrong here?
There was my mistake in views. I wrote model in serializer class instead of serializer class.
serializer_class = CorporateProfileSerializer

Adding extra fields to UserAdmin

i have this custom class
class CustomUserAdmin(UserAdmin):
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'email', 'password1', 'password2', 'location')}
),
)
fieldsets = (
(None, {'fields': ('username', 'password')}),
(('Personal info'), {'fields': ('first_name', 'last_name', 'email', 'location')}),
(('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(('Important dates'), {'fields': ('last_login', 'date_joined')}),
(('Groups'), {'fields': ('groups',)}),
)
#UserAdmin.list_display += ('location',)
add_form = MyUserCreationForm
form = MyUserChangeForm
It works fine, untill i uncomment this line
UserAdmin.list_display += ('location',)
then it gives me this error:
CustomUserAdmin.list_display[5], 'location' is not a callable or an attribute of 'CustomUserAdmin' or found in the model 'User'.
any help?
[Edit]
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
location = models.CharField(max_length=30)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
You are not going to modify UserAdmin right?
Supposing that location is an actual field of CustomUser, try to use
list_display = UserAdmin.list_display + ('location',)
EDIT: simpler answer
Use the standard django way to show custom things in the list_display:
class CustomUserAdmin(UserAdmin):
# other things
def user_location(self, u):
try:
return u.get_profile().location
except:
return ''
user_location.short_description = 'Location'
list_display = UserAdmin.list_display + ('user_location',)
EDIT: more info
Anyway, if you are extending the UserForm just for the sake of adding the profile fields, you should look into this link: http://www.thenestedfloat.com/articles/displaying-custom-user-profile-fields-in-djangos-admin/index.html to take advantages of inlines and avoid recreating the whole Form from scratch.

Categories