[Django]-Add a custom button to a Django application's admin page

15šŸ‘

āœ…

Messing with the admin forms can be complicated but iā€™ve commonly found that adding links, buttons, or extra info is easy and helpful. (Like a list of links to related objects witout making an inline, esp for things that are more viewed than edited).

From Django docs

Because of the modular design of the admin templates, it is usually
neither necessary nor advisable to
replace an entire template. It is
almost always better to override only
the section of the template which you
need to change.

This will add a list over the top of the form.

Place in templates/admin/[your_app]/[template_to_override]:

{% extends "admin/change_form.html" %}

{% block form_top %}

{% for item in original.items %}
  {{ item }}
{% endfor %}

{% endblock %}
šŸ‘¤Lincoln B

11šŸ‘

Django1.10:

1) Override admin/submit_line.html:

{% load i18n admin_urls %}
<div class="submit-row">
{% if extra_buttons %}
    {% for button in extra_buttons %}
        {{ button }}
    {% endfor %}
{% endif %}
{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %}
{% if show_delete_link %}
    {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
    <p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">{% trans "Delete" %}</a></p>
{% endif %}
{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" />{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" />{% endif %}
</div>

This assumes, of course, that buttonā€˜s string representation is an appropriate browser input or button element, and is marked safe with django.utils.safestring.mark_safe. Alternatively, you could use the safe template filter or access the attributes of button directly to construct the <input>. In my opinion, itā€™s better to isolate such things to the python level.

2) Override MyModelAdmin.change_view:

def change_view(self, request, object_id, form_url='', extra_context=None):
    extra_context = extra_context or self.extra_context()
    return super(PollAdmin, self).change_view(
        request, object_id, form_url, extra_context=extra_context,
    )

This method enables you to add buttons to any ModelAdmin easily. Alternatively to step (1), you could extend admin/change_form.html and override block submit_row. This would be slightly more verbose due to extra tags required in the template.

If you want the extra action available across all of your models (or a specific subset) then subclass ModelAdmin with the desired functionality (an example would be to add archiving to your models. You could even add an override for deleteā€“and the other default buttonsā€“so that the mode is archived instead of deleted; this would require some template modifications)

šŸ‘¤DylanYoung

2šŸ‘

You can also use django-admin-tools, which allows you to easily customize the admin front page like a dashboard. Using a LinkList, you can point to some view method and check if the user is authenticated. It goes like thies:

# dashboard.py (read more about how to create one on django-admin-tools docs)
class CustomIndexDashboard(Dashboard):
    """
    Custom index dashboard for captr.
    """
    def init_with_context(self, context):
        self.children.append(modules.LinkList(
            _('Tasks'),
            children=[
                ['Your task name', '/task']
            ]
        ))

# urls.py (mapping uri to your view function)
urlpatterns += patterns('yourapp.views',
    (r'^task$', 'task'),
)

# views.py
def task(request):
    if request.user.is_authenticated():
        update_definitions_task.delay() # do your thing here. in my case I'm using django-celery for messaging

    return redirect('/admin')

1šŸ‘

You might consider adding a custom admin action for this kind of object (similar to the built in ā€˜deleteā€™), if appropriate. Some benefits include: ā€œpure Djangoā€, not having to mess with templates, and being able to act on multiple objects at once.

Djangoā€™s admin lets you write and register ā€œactionsā€ ā€“ simple
functions that get called with a list of objects selected on the
change list page. If you look at any change list in the admin, youā€™ll
see this feature in action; Django ships with a ā€œdelete selected
objectsā€ action available to all models.

https://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/

I got the idea from this article on how to add a custom action button, which is another answer all together. I was able to get by with the simpler built-in actions though.

https://medium.com/@hakibenita/how-to-add-custom-action-buttons-to-django-admin-8d266f5b0d41

šŸ‘¤John Lehmann

-31šŸ‘

Donā€™t mess with the admin pages.

  1. Create an ā€œapplicationā€ for this. Yes, your function is just a ā€œroutineā€. Thatā€™s okay. Many smaller applications are a good thing.

  2. This application has nothing new in models.py. No new model. Zero lines of code.

  3. This application has a useful URL in urls.py. Something that can be used to display this admin page. One URL. Not many lines of code (less than a dozen.)

  4. This application has one view function in views.py. On ā€œGETā€, this view function presents the form. On ā€œPOSTā€, this view function does the ā€œroutineā€. This is the ā€œheartā€ of your application. The GET ā€” of course ā€” simply returns the template for display. The POST does the real work, and returns a final status or something.

This view function is protected with a decorator so that only an admin can execute it.
See http://docs.djangoproject.com/en/1.2/topics/auth/#django.contrib.auth.decorators.user_passes_test. You want to write a test for being an admin. lambda u: u.is_staff is probably it.

  1. This application has one template, presented by the GET and POST. That template has your form with your button. The one you canā€™t add to admin easily.

  2. The tests.py is a test case with two users, one who is an admin and one who is not an admin.

No messing with built-in admin pages.

šŸ‘¤S.Lott

Leave a comment