Django admin different inlines for change and add view
I need separate views for add and change page. In add page I'd like to exclude some fields from inline formset. I've prepared two TabularInline classes, one of开发者_开发知识库 them contains property 'exclude'. I tried to use them as follows:
class BoxAdmin(admin.ModelAdmin):
def change_view(self, request, obj_id):
self.inlines=[ItemChangeInline,]
return super(BoxAdmin, self).change_view(self.request, obj_id)
def add_view(self, request):
self.inlines=[ItemAddInline,]
return super(BoxAdmin, self).add_view(self, request)
with no effect (no inline is shown at all).
It works with Django 1.5+ and seems fine & elegant:
// admin.py
class BoxAdmin(ModelAdmin):
inlines = ()
def change_view(self, request, object_id, form_url='', extra_context=None):
self.inlines = (ItemChangeInline, )
return super(BoxAdmin, self).change_view(request, object_id)
def add_view(self, request, form_url='', extra_context=None):
self.inlines = (ItemAddInline, )
return super(BoxAdmin, self).add_view(request)
hope it can be useful for anyone
Here is the code that seems to be working:
class BoxAdmin(admin.ModelAdmin):
def change_view(self, request, obj_id):
self.inlines=[ItemChangeInline,]
for inline_class in self.inlines:
inline_instance = inline_class(self.model, self.admin_site)
self.inline_instances.append(inline_instance)
return super(BoxAdmin, self).change_view(request, obj_id)
def add_view(self, request):
self.inlines=[ItemAddInline,]
for inline_class in self.inlines:
inline_instance = inline_class(self.model, self.admin_site)
self.inline_instances.append(inline_instance)
return super(BoxAdmin, self).add_view(request)
However, this looks inelegant, cause this part:
for inline_class in self.inlines:
inline_instance = inline_class(self.model, self.admin_site)
self.inline_instances.append(inline_instance)
is a copy-paste from init method of admin.ModelAdmin (so it is run twice).
Why in add_view you have .add_view(self, request)
and in change view you have .change_view(self.request, ..)
? I believe, you don't need self in add_view, since you use super.
I had a situation where I needed to show an Inline based on the admin site that you were on for a given story.
Expanding on alekwisnia's answer, I was able to get dynamic inlines working for Django 1.3 using the following code:
In highlights/admin.py
class HighlightInline(generic.GenericTabularInline):
model = Highlight
extra = 1
max_num = 4
fields = ('order', 'highlight')
template = 'admin/highlights/inline.html'
class HighlightAdmin(admin.ModelAdmin):
def regulate_highlight_inlines(self):
highlights_enabled = Setting.objects.get_or_default('highlights_enabled', default='')
highlight_inline_instance = HighlightInline(self.model, self.admin_site)
highlight_found = any(isinstance(x, HighlightInline) for x in self.inline_instances)
if highlights_enabled.strip().lower() == 'true':
if not highlight_found:
self.inline_instances.insert(0, highlight_inline_instance)
else:
if highlight_found:
self.inline_instances.pop(0)
print self.inline_instances
def change_view(self, request, object_id, form_url='', extra_context=None):
self.regulate_highlight_inlines()
return super(HighlightAdmin, self).change_view(request, object_id)
def add_view(self, request, form_url='', extra_context=None):
self.regulate_highlight_inlines()
return super(HighlightAdmin, self).add_view(request, form_url, extra_context)
In story/admin.py
class StoryAdmin(HighlightAdmin):
One thing to note is that I'm not merely manipulating inline classes(HighlightInline) but rather, I'm changing inline instances(HighlightInline(self.model, self.admin_site)). This is because django has already constructed a list of inline instances based on a list of inline classes during the initial construction of the admin class.
Another solution to Django 1.3
class BoxAdmin(admin.ModelAdmin):
def change_view(self, request, object_id, form_url='', extra_context=None):
self.inline_instances = [ItemChangeInline(self.model, self.admin_site)]
return super(BoxAdmin, self).change_view(request, object_id, extra_context)
def add_view(self, request, form_url='', extra_context=None):
self.inline_instances = [ItemAddInline(self.model, self.admin_site)]
return super(BoxAdmin, self).add_view(request, form_url, extra_context)
Inspired by you guys answer, I was able to add more custom views to the admin.site.
Many times, just want add
and change
pages of different settings, not real extra views
# admin.py
class FooAdmin(admin.ModelAdmin):
....
def edit_tag(self, obj): # add a Link tag to change-list page
return mark_safe('<a href="{}?edit=True">Edit</a>'.format(obj.get_absolute_url()))
edit_tag.short_description = u'Extra Action'
def change_view(self, request, object_id, form_url='', extra_context=None):
if request.GET.get('edit', False):
self.readonly_fields = (
'total_amount',
)
self.inlines = []
else:
self.readonly_fields = (
'name', 'client', 'constructor', 'total_amount'
)
self.inlines = [TransactionInline]
return super(ProjectAdmin, self).change_view(request, object_id)
def add_view(self, request, form_url='', extra_context=None):
self.readonly_fields = (
'total_amount',
)
self.inlines = []
return super(ProjectAdmin, self).add_view(request)
After this I'll have three views:
add view - without inline formset, no need to add related objects.
change view 1 - with inline formset, only for adding inline data(related objects), the the object's field is readonly.
change view 2 - without inline formset, only for changing the object.
Really simple, and we can do more, thanks everyone.
精彩评论