A Django app for easily adding object tools in the Django admin

Overview

Django Object Actions

Build Status

If you've ever tried making admin object tools you may have thought, "why can't this be as easy as making Django Admin Actions?" Well now they can be.

Quick-Start Guide

Install Django Object Actions:

$ pip install django-object-actions

Add django_object_actions to your INSTALLED_APPS so Django can find our templates.

In your admin.py:

from django_object_actions import DjangoObjectActions

class ArticleAdmin(DjangoObjectActions, admin.ModelAdmin):
    def publish_this(self, request, obj):
        publish_obj(obj)
    publish_this.label = "Publish"  # optional
    publish_this.short_description = "Submit this article"  # optional

    change_actions = ('publish_this', )

Usage

Defining new &tool actions is just like defining regular admin actions. The major difference is the functions for django-object-actions will take an object instance instead of a queryset (see Re-using Admin Actions below).

Tool actions are exposed by putting them in a change_actions attribute in your admin.ModelAdmin. You can also add tool actions to the main changelist views too. There, you'll get a queryset like a regular admin action:

from django_object_actions import DjangoObjectActions

class MyModelAdmin(DjangoObjectActions, admin.ModelAdmin):
    def toolfunc(self, request, obj):
        pass
    toolfunc.label = "This will be the label of the button"  # optional
    toolfunc.short_description = "This will be the tooltip of the button"  # optional

    def make_published(modeladmin, request, queryset):
        queryset.update(status='p')

    change_actions = ('toolfunc', )
    changelist_actions = ('make_published', )

Just like admin actions, you can send a message with self.message_user. Normally, you would do something to the object and return to the same url, but if you return a HttpResponse, it will follow it (hey, just like admin actions!).

If your admin modifies get_urls, change_view, or changelist_view, you'll need to take extra care because django-object-actions uses them too.

Re-using Admin Actions

If you would like a preexisting admin action to also be an object action, add the takes_instance_or_queryset decorator to convert object instances into a queryset and pass querysets:

from django_object_actions import DjangoObjectActions, takes_instance_or_queryset

class RobotAdmin(DjangoObjectActions, admin.ModelAdmin):
    # ... snip ...

    @takes_instance_or_queryset
    def tighten_lug_nuts(self, request, queryset):
        queryset.update(lugnuts=F('lugnuts') - 1)

    change_actions = ['tighten_lug_nuts']
    actions = ['tighten_lug_nuts']

Customizing Object Actions

To give the action some a helpful title tooltip, add a short_description attribute, similar to how admin actions work:

def increment_vote(self, request, obj):
    obj.votes = obj.votes + 1
    obj.save()
increment_vote.short_description = "Increment the vote count by one"

By default, Django Object Actions will guess what to label the button based on the name of the function. You can override this with a label attribute:

def increment_vote(self, request, obj):
    obj.votes = obj.votes + 1
    obj.save()
increment_vote.label = "Vote++"

If you need even more control, you can add arbitrary attributes to the buttons by adding a Django widget style attrs attribute:

def increment_vote(self, request, obj):
    obj.votes = obj.votes + 1
    obj.save()
increment_vote.attrs = {
    'class': 'addlink',
}

Programmatically Disabling Actions

You can programmatically disable registered actions by defining your own custom get_change_actions() method. In this example, certain actions only apply to certain object states (e.g. You should not be able to close an company account if the account is already closed):

def get_change_actions(self, request, object_id, form_url):
    actions = super(PollAdmin, self).get_change_actions(request, object_id, form_url)
    actions = list(actions)
    if not request.user.is_superuser:
        return []

    obj = self.model.objects.get(pk=object_id)
    if obj.question.endswith('?'):
        actions.remove('question_mark')

    return actions

The same is true for changelist actions with get_changelist_actions.

Alternate Installation

You don't have to add this to INSTALLED_APPS, all you need to to do is copy the template django_object_actions/change_form.html some place Django's template loader will find it.

If you don't intend to use the template customizations at all, don't add django_object_actions to your INSTALLED_APPS at all and use BaseDjangoObjectActions instead of DjangoObjectActions.

More Examples

Making an action that links off-site:

def external_link(self, request, obj):
    from django.http import HttpResponseRedirect
    return HttpResponseRedirect(f'https://example.com/{obj.id}')

Limitations

  1. django-object-actions expects functions to be methods of the model admin. While Django gives you a lot more options for their admin actions.
  2. If you provide your own custom change_form.html, you'll also need to manually copy in the relevant bits of our change form .
  3. Security. This has been written with the assumption that everyone in the Django admin belongs there. Permissions should be enforced in your own actions irregardless of what this provides. Better default security is planned for the future.

Python and Django compatibility

See tox.ini for which Python and Django versions this supports.

Demo Admin & Docker images

You can try the demo admin against several versions of Django with these Docker images: https://hub.docker.com/r/crccheck/django-object-actions/tags

This runs the example Django project in ./example_project based on the "polls" tutorial. admin.py demos what you can do with this app.

Development

Getting started (with virtualenvwrapper):

# get a copy of the code
git clone [email protected]:crccheck/django-object-actions.git
cd django-object-actions
# set up your virtualenv (with virtualenvwrapper)
mkvirtualenv django-object-actions
# Install requirements
make install
# Hack your path so that we can reference packages starting from the root
add2virtualenv .
make test  # run test suite
make quickstart  # runs 'make resetdb' and some extra steps

This will install whatever the latest stable version of Django is. You can also install a specific version of Django and pip install -r requirements.txt.

Various helpers are available as make commands. Type make help and view the Makefile to see what other things you can do.

Similar Packages

If you want an actions menu for each row of your changelist, check out Django Admin Row Actions.

Django Object Actions is very similar to django-object-tools, but does not require messing with your urls.py, does not do anything special with permissions, and uses the same patterns as making admin actions.

Comments
  • Add label/description decorator for

    Add label/description decorator for "cleaner" code

    Perhaps it's something that only irks me, but I find that this syntax quickly becomes readable after the function goes beyond a few lines:

       def publish_this(self, request, obj):
           publish_obj(obj)
       publish_this.label = "Publish"  # optional
       publish_this.short_description = "Submit this article"  # optional
    

    I'm currently using this little decorator to take care of the labels and description which works great:

    def create_action(label=None, short_description=None):
    
        def _create_action(function):
            if label:
                function.label = label
    
            if short_description:
                function.short_description = short_description
    
            return function
    
        return _create_action
    

    Usage is like this:

        @create_action('Publish', 'Submit this article')
        def publish_this(self, request, obj):
            publish_obj(obj)
    
    opened by wolph 14
  • 404 on Django 1.7.1

    404 on Django 1.7.1

    I have implemented the DOA library exactly as indicated in the example, and am getting a 404 with the following detail:

    (model) object with primary key u'0b637de8-ae8a-4fe6-8558-369e9eed2c34/tools/mark_reject' does not exist.

    As you can see, i'm using a UUID as my primary key. Might this be a factor? How would you recommend me debugging it? I've gone into the source code and I'm afraid I'm not skilled enough to follow what's happening...

    Thanks! Would love for this to work, it would be a lifesaver...

    bug 
    opened by dbinetti 9
  • use django.urls.re_path when available

    use django.urls.re_path when available

    Use django.urls.re_path() when available, instead of the deprecated django.conf.urls.url().

    • re_path() is available since Django 2.0.
    • url() will be removed in Django 4.0.
    opened by mathiasertl 6
  • Button URL

    Button URL

    Hi guys, Quick question and sorry if it's a bit noobish...

    But how do I set the button's url?

    For example I want the button to be brought to admin/print/schedule.html

    Thanks, Ara

    opened by asivaneswaran 6
  • update individual item for instance case

    update individual item for instance case

    The docs have

        @takes_instance_or_queryset
        def tighten_lug_nuts(self, request, queryset):
            queryset.update(lugnuts=F('lugnuts') - 1)
    

    but this updates all values since queryset seems to ignore the _result_cache (as proven by the test in my first commit). I'm not sure filter(pk=...) is the right way to implement this behavior, but @takes_instance_or_queryset seems dangerous as it is now.

    opened by AlexRiina 5
  • Documented example of a custom get_object_actions() method

    Documented example of a custom get_object_actions() method

    Includes note about that context['original'] is not available when creating / adding new objects (and object actions can't be applied in that case anyways).

    opened by maestrofjp 5
  • Use a template tag for tidier templates

    Use a template tag for tidier templates

    If a user wants to use multiple admin extensions that all want to override the change form template they will need to incorporate all the template changes in their own change_form.html

    It's therefore a good idea to keep each template customization as clean and simple as possible.

    Sorry - I haven't updated the docs to mention this enhancement. If it's a blocker let me know.

    opened by andybak 5
  • feat: provide action decorator to pass label, description and atts to the admin method

    feat: provide action decorator to pass label, description and atts to the admin method

    Add an @action decorator that behave's like Django's admin.action decorator^1 to clean up customizing object actions.

    closes #115

    Also relates to #107

    opened by Alexerson 4
  • 500 on prefixing pk with

    500 on prefixing pk with "%20" in URL

    Lets say you have a model "model" inside the app "app" with object actions enabled and available for this model. Lets also assume, object app.model with pk=13 exists in the DB.

    Calling http://localhost:8000/admin/app/model/13/ works.

    Calling the detail view like this http://localhost:8000/admin/app/model/%20%2013/ results in an uncaught 500 (NoReverseMatch). The reason should be, that django allows blanks in its admin urls for the pk variable and the django-object-actions URLs don't.

    opened by tuky 4
  • Instead of getting only the checked objects, I receive query with all the entities in the table

    Instead of getting only the checked objects, I receive query with all the entities in the table

    Hello guys, Is it possible to use the check boxes in the admin UI to filter only the objects that I would like to take place in the queryset, sent to my function? I red the documentation of the package couple of times but couldn't realize how to achieve this. For the moment, it doesn't matter if I have checked something, none or all, I am getting full list of all the objects in the table. It's a great package, though, thank you for sharing it with us :) :100:

    opened by DanailDimitrovx2 3
  • fix: Objects with special symbols in primary key 404-ed

    fix: Objects with special symbols in primary key 404-ed

    for case if object in database has any of special symbols https://github.com/django/django/blob/master/django/contrib/admin/utils.py#L17 clicking on action button causes 404 error, as in SingleObjectMixin there are already parsed kwargs from url, and they are unquoted

    made unquoting kwargs

    opened by ilyachch 3
  • How is this package different than django-admin-actions?

    How is this package different than django-admin-actions?

    This is a package we're currently using. The main feature we're using is the listview actions. However, because it seems to be no longer maintained, I'm thinking of switching to another one that's maintained.

    https://github.com/lukasvinclav/django-admin-actions

    opened by aqeelat 1
  • Exception Type: TemplateDoesNotExist

    Exception Type: TemplateDoesNotExist

    Hi, I'm using the takes_instance_or_queryset decorator to re use an existing admin action. The issue is that when I run it in the change_list, the result queryset have all objects, not the custom selection in changelist, don't matter if I only select one o two items. Kind regards Ale

    opened by aConar 2
  • fix: unquote object_id when calling get_change_actions

    fix: unquote object_id when calling get_change_actions

    I was recently overriding get_change_actions() as instructed in the documentation, however I was having problems due to a model having a CharField for the primary key, and specifically values that included underscore characters. I was receiving what seemed to be invalid values in object_id which extra characters.

    By default the django admin quotes primary key values via the quote() function in "django/contrib/admin/utils.py". This is to prevent certain characters, such as underscores, in the primary key, especially if it's a CharField, from messing up the URL. Therefore, in the admin the object_id is unquoted before calling get_object() and in other cases.

    Therefore, I think object_id should also be unquoted before calling get_change_actions so that object_id is not url quoted any more, and operations such as obj = self.model.objects.get(pk=object_id) will succeed as expected.

    This PR simply does that. I tried for a short period to get tests running, but I've never installed poetry and was having issues, and just don't have time to debug it right now, so I wasn't able to write a test to confirm the behavior, apologies.

    opened by nshafer 2
  • Ability to place action buttons within fields

    Ability to place action buttons within fields

    Hi, let me start by expressing my gratitude for your efforts into this nice project !

    When actions are related to a certain field, it makes sense to have their button rendered within that field. See for instance: Reset_password_example ("Mot de passe" meaning "Password" in French).

    I've managed to make the "Reset password" button appear in the password field by dedicating the help_text to it:

    class UserChangeForm(admin_forms.UserChangeForm):
        class Meta(admin_forms.UserChangeForm.Meta):
            model = User
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            password = self.fields.get('password')
            if password:
                password.help_text = \
                    """<ul class="object-tools"><li class="objectaction-item" data-tool-name="reset_password">
                    <a href="/admin/users/guest/3/actions/reset_password/" title="" class="">Reset password</a>
                    </li></ul>
                    """
    

    Very hacky, but it hopefully provides you with a useful starting point for implementing this feature, would you consider it.

    Cheers

    opened by ngirard 0
Releases(v4.0.0)
Owner
Chris Chang
Tell a little about yourself
Chris Chang
Python books free to read online or download

Python books free to read online or download

Paolo Amoroso 3.7k Jan 08, 2023
A flat theme for Django admin interface. Modern, fresh, simple.

Django Flat Theme django-flat-theme is included as part of Django from version 1.9! 🎉 Please use this app if your project is powered by an older Djan

elky 416 Sep 22, 2022
A Django app for easily adding object tools in the Django admin

Django Object Actions If you've ever tried making admin object tools you may have thought, "why can't this be as easy as making Django Admin Actions?"

Chris Chang 524 Dec 26, 2022
Allow foreign key attributes in list_display with '__'

django-related-admin Allow foreign key attributes in Django admin change list list_display with '__' This is based on DjangoSnippet 2996 which was mad

Petr Dlouhý 62 Nov 18, 2022
xarray: N-D labeled arrays and datasets

xarray is an open source project and Python package that makes working with labelled multi-dimensional arrays simple, efficient, and fun!

Python for Data 2.8k Dec 29, 2022
A user-friendly JSON editing form for Django admin

A user-friendly JSON editing form for Django admin

Bharat Chauhan 141 Dec 30, 2022
A modern Python package manager with PEP 582 support.

A modern Python package manager with PEP 582 support.

Python Development Master(PDM) 3.6k Jan 05, 2023
StyleCLIP: Text-Driven Manipulation of StyleGAN Imagery

StyleCLIP: Text-Driven Manipulation of StyleGAN Imagery

3.3k Jan 01, 2023
BitcartCC is a platform for merchants, users and developers which offers easy setup and use.

BitcartCC is a platform for merchants, users and developers which offers easy setup and use.

BitcartCC 270 Jan 07, 2023
A python application for manipulating pandas data frames from the comfort of your web browser

A python application for manipulating pandas data frames from the comfort of your web browser. Data flows are represented as a Directed Acyclic Graph, and nodes can be ran individually as the user se

Schlerp 161 Jan 04, 2023
Drop-in replacement of Django admin comes with lots of goodies, fully extensible with plugin support, pretty UI based on Twitter Bootstrap.

Xadmin Drop-in replacement of Django admin comes with lots of goodies, fully extensible with plugin support, pretty UI based on Twitter Bootstrap. Liv

差沙 4.7k Dec 31, 2022
An administration website for Django

yawd-admin, a django administration website yawd-admin now has a live demo at http://yawd-admin.yawd.eu/. Use demo / demo as username & passowrd. yawd

Pantelis Petridis 140 Oct 30, 2021
Simple and extensible administrative interface framework for Flask

Flask-Admin The project was recently moved into its own organization. Please update your references to Flask-Admin 5.2k Dec 29, 2022

Ajenti Core and stock plugins

Ajenti is a Linux & BSD modular server admin panel. Ajenti 2 provides a new interface and a better architecture, developed with Python3 and AngularJS.

Ajenti Project 7k Jan 07, 2023
A curated list of the latest breakthroughs in AI by release date with a clear video explanation, link to a more in-depth article, and code.

A curated list of the latest breakthroughs in AI by release date with a clear video explanation, link to a more in-depth article, and code

Louis-François Bouchard 2.9k Jan 08, 2023
Disable dark mode in Django admin user interface in Django 3.2.x.

Django Non Dark Admin Disable or enable dark mode user interface in Django admin panel (Django==3.2). Installation For install this app run in termina

Artem Galichkin 6 Nov 23, 2022
A configurable set of panels that display various debug information about the current request/response.

Django Debug Toolbar The Django Debug Toolbar is a configurable set of panels that display various debug information about the current request/respons

Jazzband 7.3k Dec 31, 2022
Extends the Django Admin to include a extensible dashboard and navigation menu

django-admin-tools django-admin-tools is a collection of extensions/tools for the default django administration interface, it includes: a full feature

Django Admin Tools 731 Dec 28, 2022
Awesome Video Datasets

Awesome Video Datasets

Yunhua Zhang 462 Jan 02, 2023
FLEX (Federated Learning EXchange,FLEX) protocol is a set of standardized federal learning agreements designed by Tongdun AI Research Group。

Click to view Chinese version FLEX (Federated Learning Exchange) protocol is a set of standardized federal learning agreements designed by Tongdun AI

同盾科技 50 Nov 29, 2022