Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Admin Actions on single object

The admin actions seem to work on several items selected in the list view of django admin interface:

In my case I would like to have a simple action button on the change (one item) view.

Is there a way to make the django admin actions available there?

I know that I can walk around this problem by going to the list view, and select one item there. But it would be more nice to have it directly available.

like image 270
guettli Avatar asked Aug 14 '17 14:08

guettli


2 Answers

Create a template for your model in your app.

templates/admin/<yourapp>/<yourmodel>/change_form.html

With this example content to add a button when changing an existing object.

{% extends "admin/change_form.html" %}
{% block submit_buttons_bottom %}
    {{ block.super }}
    {% if original %} {# Only show if changing #}
        <div class="submit-row">
            <a href="{% url 'custom-model-action' original.pk %}">
                 Another action
            </a>
        </div>
    {% endif %}
{% endblock %}

Link that action to any url and redirect back to your model change object view. More information about extending admin templates.

Update: Added complete common use case for custom action on existing object

urls.py

urlpatterns = [
    url(r'^custom_model_action/(?P<object_pk>\d+)/$',
        core_views.custom_model_action, name='custom-model-action')
]

views.py

from django.urls import reverse
from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect

def custom_model_action(request, object_pk):
    messages.info(request, 'Performed custom action!')
    return HttpResponseRedirect(
       reverse('admin:<yourapp>_<yourmodel>_change', args=[object_pk])
    )
like image 161
D.Nibon Avatar answered Oct 23 '22 15:10

D.Nibon


If you realy need per-single object, I suggest you to use this solution, eg:

class Gallery(TimeStampedModel):
    title = models.CharField(max_length=200)
    attachment = models.FileField(upload_to='gallery/attachment/%Y/%m/%d')

    def __str__(self):
        return self.title

    def process_button(self):
        return ('<button id="%(id)s class="btn btn-default process_btn" '
                'data-value="%(value)s>Process</button>' % {'id': self.pk, 'value': self.attachment.url})
    process_button.short_description = 'Action'
    process_button.allow_tags = True

In your admin.py, insert process_button into list_display;

class GalleryAdmin(admin.ModelAdmin):
    list_display = ['title', 'process_button', 'created']
    search_fields = ['title', 'pk']
    ....

    class Media:
        js = ('path/to/yourfile.js', )

Then, inside yourfile.js, you can also process it..

$('.process_btn').click(function(){
    var id = $(this).attr('id');       // single object id
    var value = $(this).data('value'); // single object value
    ...
});

Hope it helpful..

like image 25
binpy Avatar answered Oct 23 '22 14:10

binpy