A subclass of this admin will let you add buttons (like history) in the change view of an entry.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | class ButtonableModelAdmin(admin.ModelAdmin):
"""
A subclass of this admin will let you add buttons (like history) in the
change view of an entry.
ex.
class FooAdmin(ButtonableModelAdmin):
...
def bar(self, obj):
obj.bar()
bar.short_description='Example button'
buttons = [ bar ]
you can then put the following in your admin/change_form.html template:
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
{% for button in buttons %}
<li><a href="{{ button.func_name }}/">{{ button.short_description }}</a></li>
{% endfor %}
<li><a href="history/" class="historylink">History</a></li>
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">View on site</a></li>{% endif%}
</ul>
{% endif %}{% endif %}
{% endblock %}
"""
buttons=[]
def change_view(self, request, object_id, extra_context={}):
extra_context['buttons']=self.buttons
return super(ButtonableModelAdmin, self).change_view(request, object_id, extra_context)
def __call__(self, request, url):
if url is not None:
import re
res=re.match('(.*/)?(?P<id>\d+)/(?P<command>.*)', url)
if res:
if res.group('command') in [b.func_name for b in self.buttons]:
obj = self.model._default_manager.get(pk=res.group('id'))
getattr(self, res.group('command'))(obj)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
return super(ButtonableModelAdmin, self).__call__(request, url)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Just what I was looking for! I'm definitely adding this to my toolbelt.
Two things:
Thanks for this!
#
Rechecked on django 1.2. It needs additional string here.
from django.utils.functional import update_wrapper
Work code below:
class ButtonableModelAdmin(admin.ModelAdmin):
buttons=[]
def change_view(self, request, object_id, extra_context={}): extra_context['buttons']=self.buttons if '/' in object_id: object_id = object_id[:object_id.find('/')] return super(ButtonableModelAdmin, self).change_view(request, object_id, extra_context)
def button_view_dispatcher(self, request, url): if url is not None: import re res=re.match('(./)?(?P<id>\d+)/(?P<command>.)', url) if res: if res.group('command') in [b.func_name for b in self.buttons]: obj = self.model._default_manager.get(pk=res.group('id')) getattr(self, res.group('command'))(obj) return HttpResponseRedirect(request.META['HTTP_REFERER'])
def get_urls(self):
#
Last corrections. Tested with Django 1.2.1.
from django.contrib import admin from django.http import HttpResponseRedirect
class ButtonableModelAdmin(admin.ModelAdmin):
#
I found this snippet (and arvid's 1.2 updates) very helpful. However, it does not work in 1.3 due to the the change to "Callables in templates" (see the 1.3 changelist docs). This means the items in buttons are being evaluated in the template for loop, so func_name and short_description are not available since "button" is now automatically "button()".
My quick workaround:
In FooAdmin: Instead of:<br /> buttons = [bar]<br /> use:<br /> buttons = [(bar.func_name, bar.short_description), ]
In arvid's get_urls use but[0] instead of but.func_name
And in the template use button.0 and button.1 instead of button.func_name and button.short_description
#
For django v 1.4 (form_url argument was added to change_view):
#
Updated for Django 1.8 and incorporated the workarounds above.
Admin class:
admin/my_app/change_form.html:
#
Please login first before commenting.