Not all fields are showing correctly in django admin - python

I've added a plan field to my custom Account class, but cannot get it to show on the individual account page in the django admin. It shows correctly in table of all accounts in the list view (as denoted by list_display), but does not show on each individual account page.
Here's my Account model:
class Account(AbstractUser):
PLANS = (
("free", "free"),
("pro", "pro")
)
plan = models.CharField(max_length=10, choices=PLANS, default="free")
def __str__(self) -> str:
return self.first_name
And my admin file:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from accounts.models import Account
from subscribers.models import Subscriber
class SubscriberInline(admin.TabularInline):
model = Subscriber
extra = 0
class AccountAdmin(UserAdmin):
inlines = [SubscriberInline, ]
list_display = ("first_name", "plan", "email")
# fields = ("first_name", "plan", "email")
admin.site.register(Account, AccountAdmin)
Why does this happen?
Is the problem related to the custom Account class which inherits from the AbstractUser model? I thought to add fields to the AccountAdmin class, but that just returns the below error:
ERRORS:
<class 'accounts.admin.AccountAdmin'>: (admin.E005) Both 'fieldsets' and 'fields' are specified.
The plan field also doesn't show in the admin panel when trying to create a new account (mind you, neither do most of the other fields as it only asks for the username, password1 and password2 fields, and the option to add new subscribers to the table, but other fields like first_name etc can be edited in the admin after creation).
Thanks
UPDATE:
Adding user #bdbd's suggested changes seems to not make a difference to the admin area - am I adding this incorrectly? Here's my admin.py after adding #bdbd's changes:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from accounts.models import Account
from subscribers.models import Subscriber
from django.contrib.auth.forms import UserChangeForm
from django import forms
PLANS = (
("free", "free"),
("pro", "pro")
)
class MyAccountChangeForm(UserChangeForm):
plan = forms.ChoiceField(choices=PLANS)
class SubscriberInline(admin.TabularInline):
model = Subscriber
extra = 0
class AccountAdmin(UserAdmin):
form = MyAccountChangeForm
inlines = [SubscriberInline, ]
list_display = ("first_name", "plan", "email")
# #todo: bug! plan field not showing in django admin on individual account pages
admin.site.register(Account, AccountAdmin)
UPDATE 2:
Screenshots of admin area:

You should not extend from UserAdmin. Instead, you should create your own model admin class which extends from admin.ModelAdmin.
Then you should register your model separately.
class AccountAdmin(admin.ModelAdmin):
...
admin.site.register(Account, AccountAdmin)
As necessary, you can customize AccountAdmin to get the effect you want. You can peek at the UserAdmin source code to see how it is customized, if you want your admin view to behave similarly.

You need to override the default form that is being used by UserAdmin and add your field like so:
from django.contrib.auth.forms import UserChangeForm
from django import forms
class MyAccountChangeForm(UserChangeForm):
plan = forms.ChoiceField(choices=PLANS)
Then assign the form to your admin:
class AccountAdmin(UserAdmin):
form = MyAccountChangeForm

Related

How to add some extra fields to the user in django-cms? (in django admin panel)

I would like to add some extra fields to user in django-cms (in django admin panel). How to do this in the simplest way?
Need to add two fields user bio and image. And can i use this in frontend to show a page with all the user info?
From the django docs
Create you custom user model like this
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
Change the admin file like this
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
OR
Another option is to define a custom user model. For more details please visit https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#a-full-example
Taken from Django documentation:
The simplest way would be to create what is often called a profile model. So for your example you would create something like
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User)
bio = models.TextField()
image = models.ImageField()
Then, for seeing this in the admin panel, you would reregister admin for the User
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Profile
class UserProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
As far as showing this in frontend, you can use User as well as Profile the same way you would use other Django models.

Customize UserAdmin multiple times

I'd like to display custom models in the user admin backend from multiple apps.
I can do that for just one app with the classical admin.py commands :
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
However, the following app replaces all the previous registered models with its own, and so on…
Is there a clean way to append models in the user admin backend ?
It's like the app's admin.py must be aware of all previous customizations made, and register them all again.
I would suggest importing all your inlines into one of your app's admin.py, and defining the user admin there.
from myapp.admin import MyInline
from my_other_app.admin import MyOtherInline
# Define a new User admin
class MyUserAdmin(UserAdmin): # I would avoid using the same name
inlines = (MyInline, MyOtherInline)
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Django doesn't have a mechanism to register additional inlines with a model admin automatically. You could probably create one, but the code might be fragile. I like the explicit approach above.

How to move model to the other section in Django's site admin

Is it possible to move default Groups model from 'Authentication and Authoriation' section (on the Django admin site) to custom one and how to achieve that?
Let's start from the beginning in the other words.
I have a very simple application 'accounts' in my Django project.
models.py file looks like below:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
def __str__(self):
return self.email
serializers.py file:
from rest_framework import serializers
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
class UserSerializer(serializers.HyperlinkedModelSerializer):
groups = serializers.HyperlinkedRelatedField(
many=True,
required=False,
read_only=True,
view_name="group-detail"
)
class Meta:
model = get_user_model()
exclude = ('user_permissions',)
Now, on the admin site I have two sections: 'Accounts' and 'Authentication and Authorization'. 'Accounts' section contains my 'Users' table (for User model) and 'Authentication and Authorization' section contains 'Groups' table (for Django's default authorization Group model).
My question is - is it possible and how to move Groups table (model) to the 'Accounts' section?
I've even tried to create a custom 'Group' model based on Django's default auth Group model but have stuck on migration exceptions.
Is it possible to move default Groups model from 'Authentication and Authoriation' section (on the Django admin site) to custom one and how to achieve that?
Yes, it's possible.
1) You can move your model to section auth, just add to your class:
class Meta:
app_label = 'auth'
2) You can move Group and User models to your app section, for that variant need to:
Override user model and add it to your app
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
pass
also need add to your project settings AUTH_USER_MODEL = 'your_app.CustomUser'
Don't forget declare in admin.py from your app:
class UserAdmin(admin.ModelAdmin):
pass
admin.site.register(CustomUser, UserAdmin)
For group model put this code in admin.py:
from django.db.models.loading import get_models
from django.contrib.auth import models
models = get_models(models)
models[1]._meta.app_label = 'your_app'
3) You can look at django-admin-tools

Extending the user profile in Django. Admin creation of users

Good evening,
I am presently creating a site with Django and I extended the user with a user profile. I have a small problem though. Here is my situation:
I extended the user profile in order to add custom fields.
I added the model to the User Admin Model, so when I am adding a user, I can fill in directly the fields to create the profile.
Now, if I don't add ANYTHING in these new custom user fields, in the user add page, Django Admin won't throw me an error saying these fields are null (and they aren't suppose to be)
I want it to throw me an error in this User Add Admin page, so that the admins will HAVE to fill in a profile when adding a new user.
ALL the users will be added in the Admin Panel.
Is this possible? Thanks a lot!
in admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.auth.models import User
from accounts.models import UserProfile
class UserProfileInline(admin.TabularInline):
model = UserProfile
class UserAdmin(DjangoUserAdmin):
inlines = [ UserProfileInline,]
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
In model.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
employee_number = models.PositiveIntegerField(unique=True)
def __unicode__(self):
return 'Number'
By default, empty inline is permitted and thus no further check would be taken for an empty form. You need to override it manually:
class UserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
if self.instance.pk is None:
self.empty_permitted = False # Here
class Meta:
model = UserProfile
class UserProfileInline(admin.TabularInline):
model = UserProfile
form = UserProfileForm

Django: how to including inline model fields in the list_display?

I'm attempting to extend django's contrib.auth User model, using an inline 'Profile' model to include extra fields.
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
class Profile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profile')
avatar = '/images/avatar.png'
nickname = 'Renz'
class UserProfileInline(admin.StackedInline):
model = Profile
class UserProfileAdmin(UserAdmin):
inlines = (UserProfileInline,)
admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
This works just fine for the admin 'Change User' page, but I can't find a way to add inline model fields in the list_display. Just specifying the names of Profile fields in list_display give me an error:
UserProfileAdmin.list_display[4], 'avatar' is not a callable or an attribute of 'UserProfileAdmin' or found in the model 'User'.
I can create a callable which looks up the user in the Profile table and returns the relevant field, but this leaves me without the ability to sort the list view by the inline fields, which I really need to be able to do.
Any suggestions?
You've mentioned the only solution - creating a callable. There's currently no other way to do it, and yes this does mean you can't sort by that column.

Categories