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
An improved django-admin-tools dashboard for Django projects

django-fluent-dashboard The fluent_dashboard module offers a custom admin dashboard, built on top of django-admin-tools (docs). The django-admin-tools

django-fluent 326 Nov 9, 2022
Jet Bridge (Universal) for Jet Admin – API-based Admin Panel Framework for your application

Jet Bridge for Jet Admin – Admin panel framework for your application Description About Jet Admin: https://about.jetadmin.io Live Demo: https://app.je

Jet Admin 1.3k Dec 27, 2022
aiohttp admin is generator for admin interface based on aiohttp

aiohttp admin is generator for admin interface based on aiohttp

Mykhailo Havelia 17 Nov 16, 2022
📱 An extension for Django admin that makes interface mobile-friendly. Merged into Django 2.0

Django Flat Responsive django-flat-responsive is included as part of Django from version 2.0! ?? Use this app if your project is powered by an older D

elky 248 Sep 2, 2022
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
Firebase Admin Console is a centralized platform for easy viewing and maintenance of Firestore database, the back-end API is a Python Flask app.

Firebase Admin Console is a centralized platform for easy viewing and maintenance of Firestore database, the back-end API is a Python Flask app. A starting template for developers to customize, build, and even deploy the desired admin console for their DB.

Daqi Chen 1 Sep 10, 2022
Modern responsive template for the Django admin interface with improved functionality. We are proud to announce completely new Jet. Please check out Live Demo

Django JET Modern template for Django admin interface with improved functionality Attention! NEW JET We are proud to announce completely new Jet. Plea

Geex Arts 3.4k Dec 29, 2022
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
A jazzy skin for the Django Admin-Interface (official repository).

Django Grappelli A jazzy skin for the Django admin interface. Grappelli is a grid-based alternative/extension to the Django administration interface.

Patrick Kranzlmueller 3.4k Dec 31, 2022
A Django admin theme using Twitter Bootstrap. It doesn't need any kind of modification on your side, just add it to the installed apps.

django-admin-bootstrapped A Django admin theme using Bootstrap. It doesn't need any kind of modification on your side, just add it to the installed ap

null 1.6k Dec 28, 2022
django's default admin interface made customizable. popup windows replaced by modals. :mage: :zap:

django-admin-interface django-admin-interface is a modern responsive flat admin interface customizable by the admin itself. Features Beautiful default

Fabio Caccamo 1.3k Dec 31, 2022
Extendable, adaptable rewrite of django.contrib.admin

django-admin2 One of the most useful parts of django.contrib.admin is the ability to configure various views that touch and alter data. django-admin2

Jazzband 1.2k Dec 29, 2022
Modern theme for Django admin interface

Django Suit Modern theme for Django admin interface. Django Suit is alternative theme/skin/extension for Django administration interface. Project home

Kaspars Sprogis 2.2k Dec 29, 2022
Django application and library for importing and exporting data with admin integration.

django-import-export django-import-export is a Django application and library for importing and exporting data with included admin integration. Featur

null 2.6k Jan 7, 2023
:honey_pot: A fake Django admin login screen page.

django-admin-honeypot django-admin-honeypot is a fake Django admin login screen to log and notify admins of attempted unauthorized access. This app wa

Derek Payton 907 Dec 31, 2022
"Log in as user" for the Django admin.

django-loginas About "Login as user" for the Django admin. loginas supports Python 3 only, as of version 0.4. If you're on 2, use 0.3.6. Installing dj

Stavros Korokithakis 326 Dec 3, 2022
Visually distinguish environments in Django Admin

django-admin-env-notice Visually distinguish environments in Django Admin. Based on great advice from post: 5 ways to make Django Admin safer by hakib

Yuri Shikanov 258 Nov 30, 2022
A new style for Django admin

Djamin Djamin a new and clean styles for Django admin based in Google projects styles. Quick start Install djamin: pip install -e git://github.com/her

Herson Leite 236 Dec 15, 2022
Responsive Theme for Django Admin With Sidebar Menu

Responsive Django Admin If you're looking for a version compatible with Django 1.8 just install 0.3.7.1. Features Responsive Sidebar Menu Easy install

Douglas Miranda 852 Dec 2, 2022