If I have a view that shows a formset of users for administration purpose (easy CRUD approach for admin like admin page).
I want the instance forms to show normal data like 'username', 'first_name', 'last_name', 'email', but in empty form (adding new user) I want to add extra field for 'password'.
To be precise, in formset model table view, the admin can give password to new user but can't change or view password of existing user.
how to achieve that ?
I've tried to split fields in forms like this:
from django.forms import ModelForm, Form
class UserForm(ModelForm):
class Meta:
model = User
# change to user data only fields
fields = ['username','first_name','last_name', 'email']
class UserControlForm(ModelForm):
class Meta:
model = User
# add user permissions fields
fields = ['password','groups','is_active', 'is_superuser']
but still can't figure out how to apply the approach within formset table view
Related
I have created a CustomUser(AbstractUser) Model and in this model I want to add email id field in admin Add User Page.Currently By default first we can enter username and Password and after creating username and password we are redirected to another page where email field is available I want this email field on add User page is this possible.?
On admin django already had a BaseUserAdmin which is the default, it have 2 parts, add form and change form which both forms created from fieldsets(change form) and add_fieldsets(add form)
To add fields or remove field on add form override the BaseUserAdmin add_fieldsets:
from django.contrib.auth.admin import UserAdmin
class CustomUserAdmin(UserAdmin):
add_fieldsets = UserAdmin.add_fieldsets + (
(None, {'fields': ('email',)}),
)
If you are using a custom ModelAdmin which is a subclass of
django.contrib.auth.admin.UserAdmin, then you need to add your custom
fields to fieldsets (for fields to be used in editing users) and to
add_fieldsets (for fields to be used when creating a user)
second method: override add_fieldsets attribute itself:
class CustomUserAdmin(UserAdmin):
# 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': ('username', 'email', 'password1', 'password2'),
}),
)
Document: https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#custom-users-and-django-contrib-admin
In admin.py of your app, create a ModelAdmin and use the fields attribute to include the email field in the view.
Example:
from django.contrib import admin
from myproject.myapp.models import CustomUser
class CustomUserAdmin(admin.ModelAdmin):
fields = ('username', 'password', 'email')
admin.site.register(CustomUser,CustomUserAdmin)
In my project, I use the AbstractUser class to override the default User model so I can add extra properties. I want these properties to be added to the admin page, therefore I can view them. The code below is how I have customized my admin page so far.
forms.py:
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email', 'following', 'posts')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = ('username', 'email', 'following', 'posts', )
admin.py:
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = User
list_display = ['username', 'email', 'bio', 'profilePic',]
admin.site.register(User, CustomUserAdmin)
When I click on a user object on the admin page, I can view all the properties such as a users username and email, however I want to view properties such as following and posts, which are both ManyToManyFields.
I supply these properties in the CustomUserCreationForm and the CustomUserChangeForm, however I can't still view these properties.
Does anybody know how I can view these fields when I view or create a new user object? Thank you.
I have a User model and another Admin model which has a OneToOne relationship with User model.
I am trying to modify a field in User model while an Admin model is being created.
Here is my Serializer for admin model:
class AdminSerializer(serializers.ModelSerializer):
"""A Serizlier class for vendor """
user = UserSerializer()
class Meta:
model = models.Admin
fields = ('user', 'first_name', 'last_name', 'dob', 'gender')
# This didn't work, also user_type is a field in User model and not Admin model
read_only_fields = ('user_type',)
def create(self, validated_data): # override this method <<<
"""
Since the "user" is a read_only field, the validated data doesn't contain it.
"""
# Line that causes the error. Trying to modify User model field
validated_data['user_type'] = constants.Constants.ADMIN
return super().create(validated_data)
but I get an error:
The .create() method does not support writable nested fields by
default. Write an explicit .create() method for serializer
letzbargain_api.serializers.AdminSerializer, or set read_only=True
on nested serializer fields
How can I fix this?
If I understand your problem correctly, you want to create Admin, but want to keep Admin's user's user_type read-only.
To do that you have to make sure user_type is read-only in your specified user serializer of AdminSerializer. For example, I am writing a new serializer:
class AdminUserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ('foo', 'bar', 'user_type')
read_only_fields = ('user_type',)
Now use that one in your AdminSerializer:
class AdminSerializer(serializers.ModelSerializer):
user = AdminUserSerializer() # make sure user_type is read-only in whatever serializer you specify here
class Meta:
model = models.Admin
fields = ('user', 'first_name', 'last_name', 'dob', 'gender')
def create(self, validated_data):
user_data = validated_data.pop('user')
user = models.User.objects.create(**user_data, user_type=constants.Constants.ADMIN)
admin = models.Admin.objects.create(user=user, **validated_data)
return admin
My site makes use of Django's User Authentication User model and a custom UserProfile model to store some additional data (birthday, etc.). Is there a way to create a view in Django admin that weaves together fields from both the User and UserProfile models?
I suspect that this code snippet is not even close, but maybe it will help illustrate what I'm trying to do:
from django.contrib import admin
from django.contrib.auth.models import User
from userprofile.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('name', 'gender', 'User.email') #user.email creates the error - tried some variations here, but no luck.
admin.site.register(UserProfile, UserProfileAdmin)
Error message:
ImproperlyConfigured: UserProfileAdmin.list_display[2], 'User.email' is not a callable or an attribute of 'UserProfileAdmin' or found in the model 'UserProfile'.
Ultimately, I'm trying to create an admin view that has first & last name from UserProfile and email from User.
for displaying user email you need to have a method on UserProfile or UserProfileAdmin that returns the email
on UserProfile
def user_email(self):
return self.user.email
or on UserProfileAdmin
def user_email(self, instance):
return instance.user.email
then change your list_display to
list_display = ('name', 'gender', 'user_email')
Related docs: ModelAdmin.list_display
You could try using InlineModelAdmin to display both User and UserPofile forms in a admin view.
To display user profile information in change list you can create a new method that delegates the values from UserProfile to User model.
For example this should work more or less :)
from django.contrib import admin
from django.contrib.auth.models import User
from my_models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
fk_name = 'user'
class UserAdmin(admin.ModelAdmin):
list_display = ['get_userprofile_name', 'email']
list_select_related = True
inlines = [
UserProfileInline,
]
def get_userprofile_name(self, instance):
# instance is User instance
return instance.get_profile().name
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Using Ashoks top answer i made snippet that simplifies this process for large number of fields
class ColumnViewer(object):
pass
column_list = ('name', 'surname', )
for col in column_list:
setattr(ColumnViewer, col, lambda s,i : getattr(i, col))
#admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin, ColumnViewer):
list_display = column_list
I extended the User model in django to include several other variables, such as location, and employer. Now I'm trying to create a form that has the following fields:
First name (from User)
Last name (from User)
Location (from UserProfile, which extends User via a foreign key)
Employer (also from UserProfile)
I have created a modelform:
from django.forms import ModelForm
from django.contrib import auth
from alert.userHandling.models import UserProfile
class ProfileForm(ModelForm):
class Meta:
# model = auth.models.User # this gives me the User fields
model = UserProfile # this gives me the UserProfile fields
So, my question is, how can I create a ModelForm that has access to all of the fields, whether they are from the User model or the UserProfile model?
Hope this makes sense. I'll be happy to clarify if there are any questions.
You can either create two model forms (one for User and one for UserProfile) or create a custom form with all your fields and dispatch them in your view.
from django import forms
class ContactForm(forms.Form):
first_name = forms.CharField()
last_name = forms.CharField()
location = forms.CharField()
employer = forms.CharField()
You can't. ModelForm expects all its fields to come from a single model. Create a child of Form and pull the field definitions from the models.