Django - Custom admin page not displaying properties - django

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.

Related

Django model formset : customize empty form fields

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

How can I display the column ID in the django-admin users table?

How can I show besides the columns username, email, first name, last name, staff user a 5th column with the users ID. I think I have to write some code into admin.py like:
class CustomUserAdmin(UserAdmin):
readonly_fields = ('id',)
admin.site.register(CustomUserAdmin)
You should take advantage of ModelAdmin.list_display, docs here --> https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
class CustomUserAdmin(UserAdmin):
list_display = ('username', 'email', 'first_name', 'last_name', 'id')
readonly_fields = ('id',)
admin.site.register(User, CustomUserAdmin)
In case you incur in an AlreadyRegistered error, you should add the following prior to your admin.site.register line
admin.site.unregister(User)
class UserAdmin(admin.ModelAdmin):
list_display = ['first_name', 'last_name',....., 'user_id']
class Meta:
model = User
admin.site.register(User, UserAdmin)
Add user_id field in your list display it will show.
A little late to the party but I would like to contribute.
When I tiried the accepted solution, I realized that some functionality is lost with the User admin page (Maybe other functionalities added later on). Here is the solution for whom do not want to loose other functionalities:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
admin.site.unregister(User)
# Register your models here.
#admin.register(User)
class CustomUserAdmin(UserAdmin):
readonly_fields = ("id",)
def __init__(self, model, admin_site):
super().__init__(model, admin_site)
self.list_display = ("id",) + self.list_display
I used the default UserAdmin class and inherited from it. Than adding "id" field to the super's list_display field solved it elegantly.
Note that solution can be improved by using AUTH_USER_MODEL if you are using custom user class.

Display fields from one-to-one model

I have a User model (stock django), linked with a UserProfile via a OneToOneField. Is it possible to display data from the UserProfile in the admin, when displaying users in tabular view?
I am doing:
class UserAdmin(UserAdmin):
inlines = (UserprofileInline,)
list_display = (
'username', 'email', 'first_name', 'last_name', 'is_staff'
)
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
How can I extend the list_display parameter to specify fields belonging to the UserProfile?
For example if you have an address field in UserProfile model then you can do like this
class UserAdmin(UserAdmin):
inlines = (UserprofileInline,)
list_display = (
'username', 'email', 'first_name', 'last_name', 'is_staff','address'
)
def address(self,obj):
return obj.userprofile.address
You can register your extended model 'UserProfile' to the admin site.
In that model, you can show your fields from OneToOneField User model.
Please check this out:
One to One Field Django Admin

Override a Django generic class-based view widget

Say I have a basic CreateView form, like this, to allow new users to register on a site:
from django.contrib.auth import get_user_model
from django.http import HttpResponse
from django.views.generic import CreateView
User = get_user_model()
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
I just tried this, and found that the password field is rendered in plain text; how would I go about overriding the view so that it uses forms.PasswordInput() instead? (I realise it's probably easiest to just define the form by hand, but I'm just curious about how you'd do that.)
You could override get_form(), and modify the form to change the widget on the password field:
from django import forms
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class):
form = super(Signup, self).get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
But an even better way would be to just create a custom form class. In the custom class just set widgets on the Meta class. Like this:
from django import forms
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
widgets = {
'password': forms.PasswordInput()
}
class Signup(CreateView):
form_class = SignupForm
model = User
Usually you would put the custom form class in a forms.py file as well.
Not sure if this affected earlier versions of Django, but in more recent versions the get_form() should have a default form_class=None when overriding that method.
The updated (Python 3, Django 2.2) example would be:
from django import forms
class Signup(CreateView):
model = User
fields = ['first_name', 'last_name', 'email', 'password']
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['password'].widget = forms.PasswordInput()
return form
https://docs.djangoproject.com/en/2.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin

Django Admin: how to display fields from two different models in same view?

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