As subject, i want to hide some fields ONLY when users enter the 'CREATE' admin page for specific model.
I know that change list_display can hide fields in admin page, but it's a global setting which will take affect not only in 'CREATE' admin page, but also in 'UPDATE' admin page.
#admin.register(User)
class UserProfileAdmin(UserAdmin):
def get_fields(self, request, obj=None):
fields = super(UserProfileAdmin, self).get_fields(request, obj)
for field in fields:
if field == 'some_field_name' and obj is None:
continue
yield field
Copied from Exclude fields in Django admin for users other than superuser
def get_fieldsets(self, request, obj=None):
fieldsets = super(MediaAdmin, self).get_fieldsets(request, obj)
if not obj:
fieldsets = (
(u'other', {
'fields': ('media_public_id',)
}),
)
return fieldsets
Django now has a get_exclude method on ModelAdmin for excluding fields programmatically.
It takes the current request and the object (if any) as argument. In your case, the object argument will be none if it's a "create" page so you can use that like so:
class MyModelAdmin(admin.ModelAdmin):
def get_exclude(self, request, obj=None):
excluded = super().get_exclude(request, obj) or [] # get overall excluded fields
if not obj: # if it's a create, so no object yet
return excluded + ['extra_field_to_exclude']
return excluded # otherwise return the default excluded fields if any
Related
In "wagtail_hooks.py" I have the code below. As wagtail admin I can see the StudentModelAdmin, but as a user with restricted access to the admin interface I can't.
I would like to allow users with wagtail admin access and the specific permission below to access the student model admin. How do I go about creating the "CourseRegisterPermission" class?
from wagtail.contrib.modeladmin.options import (ModelAdmin, modeladmin_register)
from wagtail.wagtailcore import hooks
from .models import Participant
#hooks.register('register_permissions')
def view_course_registrations():
return Permission.objects.filter(codename="view_course_registrations")
class CourseRegisterPermission(PermissionHelper):
# how do I allow users with the permission to view course registrations
# to see the 'StudentModelAdmin" below?
class StudentModelAdmin(ModelAdmin):
model = Participant
menu_label = "Student Registrations"
menu_icon = "group"
search_fields = ('name', 'supervisor_name')
list_display = ('name', 'email')
list_filter = ('course',)
permission_helper_class = CourseRegisterPermission
I tried to find some examples of wagtail PermissionHelper but wasn't able to find any.
Any hint would be appreciated!
You can use the wagtail.contrib.modeladmin.helpers.PermissionHelper or wagtail.contrib.modeladmin.helpers.PagePermissionHelper permission helper classes from Wagtail's sources as an example. See methods like user_can_list, user_can_create, etc.
But... Are you sure that you need to define your own permission helper class? It seems to me that you can just create a new (or edit existing) group in the Wagtail admin and give required object permissions to your Participant model.
On my screenshot Programme is the model that I manage using ModelAdmin.
You can override some functions inside CourseRegisterPermission
class CourseRegisterPermission(PermissionHelper):
def user_can_list(self, user):
"""
Return a boolean to indicate whether `user` is permitted to access the
list view for self.model
"""
# this is just an example
return user.role == "driver"
def user_can_delete_obj(self, user, obj):
"""
Return a boolean to indicate whether `user` is permitted to 'delete'
a specific `self.model` instance.
"""
perm_codename = self.get_perm_codename('delete')
if obj.status > 0:
return False
if not self.user_has_specific_permission(user, perm_codename):
return False
if user.id == obj.id:
# users may not delete themselves
return False
You can also override the following functions:
def user_can_list(self, user):
def user_can_create(self, user):
def user_can_inspect_obj(self, user, obj):
def user_can_edit_obj(self, user, obj):
def user_can_delete_obj(self, user, obj):
def user_can_unpublish_obj(self, user, obj):
def user_can_copy_obj(self, user, obj):
Within my Users page, I would like to add more column fields to display for each user.
By default, the User page shows username, first name, last name, email, and staff status, but I would also like to add the column "Chosen Groups" to be displayed as well.
Each user can be a part of zero or more groups, so I would like to show a list of all groups (or None) that each user is a part of.
I put something together but I am not sure how to actually get the group data and put it into a "string" form for the "Chosen Groups" column.
Here was my failed attempt...
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'email', 'first_name', 'last_name', 'date_joined', 'get_groups')
def get_groups(self, object):
#code...
#User is registered by default, need to unregister than register to apply custom updates to UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Here it is:
def get_groups(self, object):
return u', '.join(g.name for g in object.groups.all()) or 'None'
get_groups.short_description = 'Chosen Groups'
To reduce the number of sql queries you can also override the get_queryset() method:
def get_queryset(self, request):
qs = super(UserAdmin, self).get_queryset(request)
return qs.prefetch_related('groups')
I have a posting object that can be either accessed in the website or the admin panel. In both, the user is automatically assigned to the post when the user posts it. In the website area, it works fine. However, it does not work in the admin area. First, I tried just having the form input there. When I try to save the object and leave the input blank, it tells me the form has no value. Then, trying to see if I just put in a random value and see if it was overwritten, I did that. However, that random value was not overwritten with the current user. If I excluded the field, when I try to save the model I get an Integrity error saying the field author 'may not be NULL', so I'm assuming my save_model() function is not firing right at all. Now the code I'm using for this I've seen all over the internet and people claim for it to work, I don't know if it's just broken now or what. Here's my code:
from django.contrib import admin
from posting.models import Posting, Categories
class PostingAdmin(admin.ModelAdmin):
list_display = ("title","author", "article","date")
exclude = ('author',)
fieldsets = (
(None, {
'fields': ('title',)
}),
('Body', {
'fields': ('article',)
}),
)
def save_model(self,request,form,obj,change):
print 'ENTERING SAVE_MODEL FUNCTION'
if not change:
obj.author = request.user
print 'OBJ.AUTHOR:' + str(obj.author)
obj.save()
print "EXITING SAVE_MODEL FUNCTION"
admin.site.register(Posting, PostingAdmin)
I added this for information only as I came across this post which made me look deeper for an issue I was having that was similar...
To pre-populate an admin field in Django 1.11 from "request" data, see below example of a models "user" field being pre-populated with the logged in user:
admin.py
class PostingAdmin(admin.ModelAdmin):
def get_changeform_initial_data(self, request):
return {'user': request.user}
This populates the field when initially adding a new "Posting Admin" (model instance) before it has been saved for the first time.
You could override the ModelAdmin.get_form, by adding the request as an attribute of the newly created form class .
class EntryAdmin(admin.ModelAdmin):
form = EntryAdminForm
def get_form(self, request, *args, **kwargs):
form = super(EntryAdmin, self).get_form(request, *args, **kwargs)
form.request = request
return form
This works for me:
from django.contrib import admin
from page.models import Page
class PageAdmin(admin.ModelAdmin):
def get_form(self, request, *args, **kwargs):
form = super(PageAdmin, self).get_form(request, *args, **kwargs)
form.base_fields['author'].initial = request.user
return form
admin.site.register(Page, PageAdmin)
I know i am a bit late for posting this solution, but like me if anyone else come across you may try:
def save_model(self, request, obj, form, change):
if getattr(obj, 'author', None) is None:
obj.author = request.user
obj.save()
is it possible to prevent certain fields to be edited after they've been saved?
They should be editable when the user creates a new item of a certain model but then when they try to open them to edit certain fields are 'blocked'.
thanks
You could override your ModelAdmin's get_readonly_fields to set certain fields readonly:
class MyAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
if obj: # when editing an object
return ['field1']
return self.readonly_fields
I want to disable editing ALL objects within a particular TabularInline instance, while still allowing additions and while still allowing editing of the parent model.
I have this trivial setup:
class SuperviseeAdmin(admin.TabularInline):
model = Supervisee
class SupervisorAdmin(admin.ModelAdmin):
inlines = [SuperviseeAdmin]
admin.site.register(Supervisor, SupervisorAdmin)
I have tried adding a has_change_permission function to SuperviseeAdmin that returns False unconditionally, but it had no effect.
I have tried setting actions = None in SuperviseeAdmin but it had no effect.
What might I be overlooking that could get this to work?
User django admin build in function has_change_permission() and return false to restrict object Edit view.
class SuperviseeAdmin(admin.TabularInline):
model = Supervisee
def has_change_permission(self, request):
return False
class SupervisorAdmin(admin.ModelAdmin):
inlines = [SuperviseeAdmin]
admin.site.register(Supervisor, SupervisorAdmin)
See this solution: Django admin: make field editable in add but not edit
Override get_readonly_fields method:
def get_readonly_fields(self, request, obj=None):
if obj: # obj is not None, so this is an edit
return ['name1',..] # Return a list or tuple of readonly fields' names
else: # This is an addition
return []
You can try creating a separate inline class (see the InlineModelAdmin docs) that uses a custom ModelForm where you can customise the the clean method to throw an error when trying to update:
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.forms import ModelForm
from myapp.models import Supervisee
class SuperviseeModelForm(ModelForm):
class Meta(object):
model = Supervisee
# other options ...
def clean(self):
if self.instance.pk:
# instance already exists
raise ValidationError('Update not allowed')
# instance doesn't exist yet, continue
return super(SuperviseeModelForm, self).clean()
class SuperviseeInline(admin.TabularInline):
model = Supervisee
form = SuperviseeModelForm
class SuperviseeAdmin(admin.ModelAdmin):
inlines = [SuperviseeInline]
just make all your fields readonly_fields in your admin.TabularInline as :
class SuperviseeAdmin(admin.TabularInline):
model = Supervisee
readonly_fields = ('your_field', 'your_field2',)
class SuperviseeAdmin(admin.TabularInline):
model = Supervisee
def __init__(self, *args, **kwargs):
super(SuperviseeAdmin, self).__init__(*args, **kwargs)
self.list_display_links = (None, )