diff options
Diffstat (limited to 'parts/django/docs/ref/contrib/admin/actions.txt')
-rw-r--r-- | parts/django/docs/ref/contrib/admin/actions.txt | 351 |
1 files changed, 0 insertions, 351 deletions
diff --git a/parts/django/docs/ref/contrib/admin/actions.txt b/parts/django/docs/ref/contrib/admin/actions.txt deleted file mode 100644 index 0fab59e..0000000 --- a/parts/django/docs/ref/contrib/admin/actions.txt +++ /dev/null @@ -1,351 +0,0 @@ -============= -Admin actions -============= - -.. versionadded:: 1.1 - -.. currentmodule:: django.contrib.admin - -The basic workflow of Django's admin is, in a nutshell, "select an object, -then change it." This works well for a majority of use cases. However, if you -need to make the same change to many objects at once, this workflow can be -quite tedious. - -In these cases, 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. For example, here's the user module from Django's built-in -:mod:`django.contrib.auth` app: - -.. image:: _images/user_actions.png - -.. warning:: - - The "delete selected objects" action uses :meth:`QuerySet.delete() - <django.db.models.QuerySet.delete>` for efficiency reasons, which has an - important caveat: your model's ``delete()`` method will not be called. - - If you wish to override this behavior, simply write a custom action which - accomplishes deletion in your preferred manner -- for example, by calling - ``Model.delete()`` for each of the selected items. - - For more background on bulk deletion, see the documentation on :ref:`object - deletion <topics-db-queries-delete>`. - -Read on to find out how to add your own actions to this list. - -Writing actions -=============== - -The easiest way to explain actions is by example, so let's dive in. - -A common use case for admin actions is the bulk updating of a model. Imagine a -simple news application with an ``Article`` model:: - - from django.db import models - - STATUS_CHOICES = ( - ('d', 'Draft'), - ('p', 'Published'), - ('w', 'Withdrawn'), - ) - - class Article(models.Model): - title = models.CharField(max_length=100) - body = models.TextField() - status = models.CharField(max_length=1, choices=STATUS_CHOICES) - - def __unicode__(self): - return self.title - -A common task we might perform with a model like this is to update an -article's status from "draft" to "published". We could easily do this in the -admin one article at a time, but if we wanted to bulk-publish a group of -articles, it'd be tedious. So, let's write an action that lets us change an -article's status to "published." - -Writing action functions ------------------------- - -First, we'll need to write a function that gets called when the action is -trigged from the admin. Action functions are just regular functions that take -three arguments: - - * The current :class:`ModelAdmin` - * An :class:`~django.http.HttpRequest` representing the current request, - * A :class:`~django.db.models.QuerySet` containing the set of objects - selected by the user. - -Our publish-these-articles function won't need the :class:`ModelAdmin` or the -request object, but we will use the queryset:: - - def make_published(modeladmin, request, queryset): - queryset.update(status='p') - -.. note:: - - For the best performance, we're using the queryset's :ref:`update method - <topics-db-queries-update>`. Other types of actions might need to deal - with each object individually; in these cases we'd just iterate over the - queryset:: - - for obj in queryset: - do_something_with(obj) - -That's actually all there is to writing an action! However, we'll take one -more optional-but-useful step and give the action a "nice" title in the admin. -By default, this action would appear in the action list as "Make published" -- -the function name, with underscores replaced by spaces. That's fine, but we -can provide a better, more human-friendly name by giving the -``make_published`` function a ``short_description`` attribute:: - - def make_published(modeladmin, request, queryset): - queryset.update(status='p') - make_published.short_description = "Mark selected stories as published" - -.. note:: - - This might look familiar; the admin's ``list_display`` option uses the - same technique to provide human-readable descriptions for callback - functions registered there, too. - -Adding actions to the :class:`ModelAdmin` ------------------------------------------ - -Next, we'll need to inform our :class:`ModelAdmin` of the action. This works -just like any other configuration option. So, the complete ``admin.py`` with -the action and its registration would look like:: - - from django.contrib import admin - from myapp.models import Article - - def make_published(modeladmin, request, queryset): - queryset.update(status='p') - make_published.short_description = "Mark selected stories as published" - - class ArticleAdmin(admin.ModelAdmin): - list_display = ['title', 'status'] - ordering = ['title'] - actions = [make_published] - - admin.site.register(Article, ArticleAdmin) - -That code will give us an admin change list that looks something like this: - -.. image:: _images/article_actions.png - -That's really all there is to it! If you're itching to write your own actions, -you now know enough to get started. The rest of this document just covers more -advanced techniques. - -Advanced action techniques -========================== - -There's a couple of extra options and possibilities you can exploit for more -advanced options. - -Actions as :class:`ModelAdmin` methods --------------------------------------- - -The example above shows the ``make_published`` action defined as a simple -function. That's perfectly fine, but it's not perfect from a code design point -of view: since the action is tightly coupled to the ``Article`` object, it -makes sense to hook the action to the ``ArticleAdmin`` object itself. - -That's easy enough to do:: - - class ArticleAdmin(admin.ModelAdmin): - ... - - actions = ['make_published'] - - def make_published(self, request, queryset): - queryset.update(status='p') - make_published.short_description = "Mark selected stories as published" - -Notice first that we've moved ``make_published`` into a method and renamed the -`modeladmin` parameter to `self`, and second that we've now put the string -``'make_published'`` in ``actions`` instead of a direct function reference. This -tells the :class:`ModelAdmin` to look up the action as a method. - -Defining actions as methods gives the action more straightforward, idiomatic -access to the :class:`ModelAdmin` itself, allowing the action to call any of the -methods provided by the admin. - -.. _custom-admin-action: - -For example, we can use ``self`` to flash a message to the user informing her -that the action was successful:: - - class ArticleAdmin(admin.ModelAdmin): - ... - - def make_published(self, request, queryset): - rows_updated = queryset.update(status='p') - if rows_updated == 1: - message_bit = "1 story was" - else: - message_bit = "%s stories were" % rows_updated - self.message_user(request, "%s successfully marked as published." % message_bit) - -This make the action match what the admin itself does after successfully -performing an action: - -.. image:: _images/article_actions_message.png - -Actions that provide intermediate pages ---------------------------------------- - -By default, after an action is performed the user is simply redirected back -to the original change list page. However, some actions, especially more -complex ones, will need to return intermediate pages. For example, the -built-in delete action asks for confirmation before deleting the selected -objects. - -To provide an intermediary page, simply return an -:class:`~django.http.HttpResponse` (or subclass) from your action. For -example, you might write a simple export function that uses Django's -:doc:`serialization functions </topics/serialization>` to dump some selected -objects as JSON:: - - from django.http import HttpResponse - from django.core import serializers - - def export_as_json(modeladmin, request, queryset): - response = HttpResponse(mimetype="text/javascript") - serializers.serialize("json", queryset, stream=response) - return response - -Generally, something like the above isn't considered a great idea. Most of the -time, the best practice will be to return an -:class:`~django.http.HttpResponseRedirect` and redirect the user to a view -you've written, passing the list of selected objects in the GET query string. -This allows you to provide complex interaction logic on the intermediary -pages. For example, if you wanted to provide a more complete export function, -you'd want to let the user choose a format, and possibly a list of fields to -include in the export. The best thing to do would be to write a small action -that simply redirects to your custom export view:: - - from django.contrib import admin - from django.contrib.contenttypes.models import ContentType - from django.http import HttpResponseRedirect - - def export_selected_objects(modeladmin, request, queryset): - selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) - ct = ContentType.objects.get_for_model(queryset.model) - return HttpResponseRedirect("/export/?ct=%s&ids=%s" % (ct.pk, ",".join(selected))) - -As you can see, the action is the simple part; all the complex logic would -belong in your export view. This would need to deal with objects of any type, -hence the business with the ``ContentType``. - -Writing this view is left as an exercise to the reader. - -.. _adminsite-actions: - -Making actions available site-wide ----------------------------------- - -.. method:: AdminSite.add_action(action[, name]) - - Some actions are best if they're made available to *any* object in the admin - site -- the export action defined above would be a good candidate. You can - make an action globally available using :meth:`AdminSite.add_action()`. For - example:: - - from django.contrib import admin - - admin.site.add_action(export_selected_objects) - - This makes the `export_selected_objects` action globally available as an - action named `"export_selected_objects"`. You can explicitly give the action - a name -- good if you later want to programatically :ref:`remove the action - <disabling-admin-actions>` -- by passing a second argument to - :meth:`AdminSite.add_action()`:: - - admin.site.add_action(export_selected_objects, 'export_selected') - -.. _disabling-admin-actions: - -Disabling actions ------------------ - -Sometimes you need to disable certain actions -- especially those -:ref:`registered site-wide <adminsite-actions>` -- for particular objects. -There's a few ways you can disable actions: - -Disabling a site-wide action -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. method:: AdminSite.disable_action(name) - - If you need to disable a :ref:`site-wide action <adminsite-actions>` you can - call :meth:`AdminSite.disable_action()`. - - For example, you can use this method to remove the built-in "delete selected - objects" action:: - - admin.site.disable_action('delete_selected') - - Once you've done the above, that action will no longer be available - site-wide. - - If, however, you need to re-enable a globally-disabled action for one - particular model, simply list it explicitly in your ``ModelAdmin.actions`` - list:: - - # Globally disable delete selected - admin.site.disable_action('delete_selected') - - # This ModelAdmin will not have delete_selected available - class SomeModelAdmin(admin.ModelAdmin): - actions = ['some_other_action'] - ... - - # This one will - class AnotherModelAdmin(admin.ModelAdmin): - actions = ['delete_selected', 'a_third_action'] - ... - - -Disabling all actions for a particular :class:`ModelAdmin` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you want *no* bulk actions available for a given :class:`ModelAdmin`, simply -set :attr:`ModelAdmin.actions` to ``None``:: - - class MyModelAdmin(admin.ModelAdmin): - actions = None - -This tells the :class:`ModelAdmin` to not display or allow any actions, -including any :ref:`site-wide actions <adminsite-actions>`. - -Conditionally enabling or disabling actions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. method:: ModelAdmin.get_actions(request) - - Finally, you can conditionally enable or disable actions on a per-request - (and hence per-user basis) by overriding :meth:`ModelAdmin.get_actions`. - - This returns a dictionary of actions allowed. The keys are action names, and - the values are ``(function, name, short_description)`` tuples. - - Most of the time you'll use this method to conditionally remove actions from - the list gathered by the superclass. For example, if I only wanted users - whose names begin with 'J' to be able to delete objects in bulk, I could do - the following:: - - class MyModelAdmin(admin.ModelAdmin): - ... - - def get_actions(self, request): - actions = super(MyModelAdmin, self).get_actions(request) - if request.user.username[0].upper() != 'J': - del actions['delete_selected'] - return actions - - |