{ "info": { "author": "Alexander Frenzel", "author_email": "alex@relatedworks.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# django-inline-actions\n\n[![pypi](https://img.shields.io/pypi/v/django-inline-actions.svg)](https://pypi.python.org/pypi/django-inline-actions) [![Build Status](https://travis-ci.org/escaped/django-inline-actions.png?branch=master)](http://travis-ci.org/escaped/django-inline-actions) [![Coverage](https://coveralls.io/repos/escaped/django-inline-actions/badge.png?branch=master)](https://coveralls.io/r/escaped/django-inline-actions) ![python version](https://img.shields.io/pypi/pyversions/django-inline-actions.svg) ![Project status](https://img.shields.io/pypi/status/django-inline-actions.svg) ![license](https://img.shields.io/pypi/l/django-inline-actions.svg)\n\ndjango-inline-actions adds actions to the InlineModelAdmin and ModelAdmin changelist.\n\n\n## Screenshot\n\n![Changelist example](https://raw.githubusercontent.com/escaped/django-inline-actions/master/example_changelist.png)\n![Inline example](https://raw.githubusercontent.com/escaped/django-inline-actions/master/example_inline.png)\n\n## Installation\n\n**NOTE** If you are on `django<2.0`, you have to use `django-inline-actions<2.0`.\n\n1. Install django-inline-actions\n\n pip install django-inline-actions\n\n2. Add `inline_actions` to your `INSTALLED_APPS`.\n\n\n## Integration\n\nAdd the `InlineActionsModelAdminMixin` to your `ModelAdmin`.\nIf you want to have actions on your inlines, add the `InlineActionMixin` to your `InlineModelAdmin`.\nEach action is implemented as a method on the `ModelAdmin`/`InlineModelAdmin` and **must have** the following signature.\n\n def action_name(self, request, obj, parent_obj=None):\n\n| Argument | Description |\n|--------------|---------------------------------------------------|\n| `request` | current request |\n| `obj` | instance on which the action was triggered |\n| `parent_obj` | instance of the parent model, only set on inlines |\n\nand should return `None` to return to the current changeform or a `HttpResponse`.\nFinally, add your method name to list of actions `inline_actions` defined on the corresponding `ModelAdmin`.\nIf you want to disable the *actions* column, you have to explicitly set `inline_actions = None`.\nTo add your actions dynamically, you can use the method `get_inline_actions(self, request, obj=None)` instead.\n\nThis module is bundled with two actions for viewing (`inline_actions.actions.ViewAction`) and deleting (`inline_actions.actions.DeleteAction`).\nJust add these classes to your admin and you're done.\n\nAdditionally, you can add methods to generate a custom label and CSS classes per object.\nIf you have an inline action called `action_name` then you can define\n\n def get_action_name_label(self, obj):\n return 'some string'\n\n def get_action_name_css(self, obj):\n return 'some string'\n\n| Argument | Description |\n|----------|--------------------------------------------|\n| `obj` | instance on which the action was triggered |\n\nEach defined method has to return a string.\n\n\n### Example 1\n\nImagine a simple news application with the following `admin.py`.\n\n from django.contrib import admin\n from inline_actions.admin import InlineActionsMixin\n from inline_actions.admin import InlineActionsModelAdminMixin\n\n from .models import Article, Author\n\n\n class ArticleInline(InlineActionsMixin,\n admin.TabularInline):\n model = Article\n inline_actions = []\n\n def has_add_permission(self):\n return False\n\n\n @admin.register(Author)\n class AuthorAdmin(InlineActionsModelAdminMixin,\n admin.ModelAdmin):\n inlines = [ArticleInline]\n list_display = ('name',)\n\n\n @admin.register(Article)\n class AuthorAdmin(admin.ModelAdmin):\n list_display = ('title', 'status', 'author')\n\n\nWe now want to add two simple actions (`view`, `unpublish`) to each article within the `AuthorAdmin`.\nThe `view` action redirects to the changeform of the selected instance.\n\n from django.core.urlresolvers import reverse\n from django.shortcuts import redirect\n\n\n class ArticleInline(InlineActionsMixin,\n admin.TabularInline):\n # ...\n inline_actions = ['view']\n # ...\n\n def view(self, request, obj, parent_obj=None):\n url = reverse(\n 'admin:{}_{}_change'.format(\n obj._meta.app_label,\n obj._meta.model_name,\n ),\n args=(obj.pk,)\n )\n return redirect(url)\n view.short_description = _(\"View\")\n\nSince `unpublish` depends on `article.status` we must use `get_inline_actions` to add this action dynamically.\n\n from django.contrib import admin, messages\n from django.utils.translation import ugettext_lazy as _\n\n\n class ArticleInline(InlineActionsMixin,\n admin.TabularInline):\n # ...\n def get_inline_actions(self, request, obj=None):\n actions = super(ArticleInline, self).get_inline_actions(request, obj)\n if obj:\n if obj.status == Article.PUBLISHED:\n actions.append('unpublish')\n return actions\n\n def unpublish(self, request, obj, inline_obj):\n inline_obj.status = Article.DRAFT\n inline_obj.save()\n messages.info(request, _(\"Article unpublished\"))\n unpublish.short_description = _(\"Unpublish\")\n\n\nAdding `inline_actions` to the changelist works similar. See the sample project for further details (`test_proj/blog/admin.py`).\n\n### Example 2\n\nInstead of creating separate actions for publishing and unpublishing, we might prefer an action, which toggles between those two states.\n`toggle_publish` implements the behaviour described above.\n\n def toggle_publish(self, request, obj, parent_obj=None):\n if obj.status == Article.DRAFT:\n obj.status = Article.PUBLISHED\n else:\n obj.status = Article.DRAFT\n\n obj.save()\n\n if obj.status == Article.DRAFT:\n messages.info(request, _(\"Article unpublished.\"))\n else:\n messages.info(request, _(\"Article published.\"))\n\nThis might leave the user with an ambiguous button label as it will be called `Toggle publish` regardless of the internal state.\nWe can specify a dynamic label by adding a special method `get_ACTIONNAME_label`.\n\n def get_toggle_publish_label(self, obj):\n if obj.status == Article.DRAFT:\n return 'Publish'\n return 'Unpublish'\n\n\nSo assuming an object in a row has `DRAFT` status, then the button label will be `Toggle publish` and `Toggle unpublish` otherwise.\n\nWe can go even fancier when we create a method that will add css classes for each object depending on a status like:\n\n\n def get_toggle_publish_css(self, obj):\n if obj.status == Article.DRAFT:\n return 'btn-red'\n return 'btn-green'\n\nYou can make it more eye-candy by using `btn-green` that makes your button green and `btn-red` that makes your button red.\nOr you can use those classes to add some javascript logic (i.e. confirmation box).\n\n\n## Example Application\n\nYou can see `django-inline-actions` in action using the bundled test application `test_proj`.\nUse [`poetry`](https://poetry.eustace.io/) to run it.\n\n git clone https://github.com/escaped/django-inline-actions.git\n cd django-inline-actions/\n poetry install\n poetry run pip install Django\n cd test_proj\n poetry run ./manage.py migrate\n poetry run ./manage.py createsuperuser\n poetry run ./manage.py runserver\n\nOpen [`http://localhost:8000/admin/`](http://localhost:8000/admin/) in your browser and create an author and some articles.\n\n\n## How to test your actions?\n\nThere are two ways how you could write tests for your actions.\nWe will use [pytest](https://docs.pytest.org/en/latest/) for the following examples.\n\n\n### Test the action itself\n\nBefore we can call our action on the admin class itself, we have to instantiate the admin environment and pass it to the `ModelAdmin` together with an instance of our model.\nTherefore, we implement a fixture called `admin_site`, which is used on each test.\n\n import pytest\n from django.contrib.admin import AdminSite\n\n from yourapp.module.admin import MyAdmin\n\n\n @pytest.fixture\n def admin_site():\n return AdminSite()\n\n @pytest.mark.django_db\n def test_action_XXX(admin_site):\n \"\"\"Test action XXX\"\"\"\n fake_request = {} # you might need to use a RequestFactory here\n obj = ... # create an instance\n\n admin = MyAdmin(obj, admin_site)\n\n admin.render_inline_actions(article)\n response = admin.action_XXX(fake_request, obj)\n # assert the state of the application\n\n\n### Test the admin integration\n\nAlternatively, you can test your actions on the real Django admin page.\nYou will have to log in, navigate to the corresponding admin and trigger a click on the action.\nTo simplify this process you can use [django-webtest](https://github.com/django-webtest/django-webtest).\nExample can be found [here](https://github.com/escaped/django-inline-actions/blob/76b6f6b83c6d1830c2ad71512cd1e85362936dbd/test_proj/blog/tests/test_inline_admin.py#L146).\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/escaped/django-inline-actions", "keywords": "", "license": "BSD-3-Clause", "maintainer": "Alexander Frenzel", "maintainer_email": "alex@relatedworks.com", "name": "django-inline-actions", "package_url": "https://pypi.org/project/django-inline-actions/", "platform": "", "project_url": "https://pypi.org/project/django-inline-actions/", "project_urls": { "Documentation": "https://github.com/escaped/django-inline-actions/blob/master/README.md", "Homepage": "https://github.com/escaped/django-inline-actions", "Repository": "https://github.com/escaped/django-inline-actions" }, "release_url": "https://pypi.org/project/django-inline-actions/2.2.0/", "requires_dist": null, "requires_python": ">=3.5,<4.0", "summary": "django-inline-actions adds actions to each row of the ModelAdmin or InlineModelAdmin.", "version": "2.2.0" }, "last_serial": 5394815, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "9aaff74725320f42a3c15701946ebc98", "sha256": "61d2f9c0aa85faff99decf0a13555920b48e7f60ecd464bc351f32e23c8fa2db" }, "downloads": -1, "filename": "django_inline_actions-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9aaff74725320f42a3c15701946ebc98", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 8861, "upload_time": "2016-05-09T15:18:10", "url": "https://files.pythonhosted.org/packages/bf/5d/6a6331da8c76250268054bac0be1d302818552a0a70c40f29c42fbdc08b6/django_inline_actions-0.1.0-py2.py3-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "4cbfb7d86590d76d3dac0b152294667b", "sha256": "e379d83679268f5f243573cba72d4005112cb474b88cfa5b95fe686e880aaea5" }, "downloads": -1, "filename": "django_inline_actions-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "4cbfb7d86590d76d3dac0b152294667b", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 9018, "upload_time": "2016-09-27T16:14:59", "url": "https://files.pythonhosted.org/packages/ee/7c/f80d49872254f33be4b13ca0ed702356e0a04f31a651f62a1e066dc529b5/django_inline_actions-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3760d421577795273786447ab9101f16", "sha256": "3374374c2bc3b962c9ab1d86ddace9a02ef7c556c3e374e0c32e59935e7342f7" }, "downloads": -1, "filename": "django-inline-actions-0.1.1.tar.gz", "has_sig": false, "md5_digest": "3760d421577795273786447ab9101f16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20454, "upload_time": "2016-09-27T16:11:42", "url": "https://files.pythonhosted.org/packages/56/df/12f92c7c946af4892e182e32d029d6b582b6feaeaead00df3f78d8cc989b/django-inline-actions-0.1.1.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "f6623417c1659462633a9c68b2d994e8", "sha256": "99061267176c4d6f448df64678ebc8c579d4f31ced67dd70443aaf5f0e0aa185" }, "downloads": -1, "filename": "django_inline_actions-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f6623417c1659462633a9c68b2d994e8", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 10852, "upload_time": "2016-11-12T10:04:46", "url": "https://files.pythonhosted.org/packages/67/1f/97c7a399bf02c020b567e741c82dfab028da6eed15dd6569bb4194ffab31/django_inline_actions-1.0.0-py2.py3-none-any.whl" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "80afb37a4a8596007bbd5f677e55cf03", "sha256": "507c5be8fad5ca4b7b330f3ef3ff055cdad5e385fd0e58aaab838780617aa2d7" }, "downloads": -1, "filename": "django_inline_actions-1.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "80afb37a4a8596007bbd5f677e55cf03", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12251, "upload_time": "2017-07-21T10:07:44", "url": "https://files.pythonhosted.org/packages/ff/54/4ffd92e65582797a16e8e30343bc73f2f13778596b0a5527a1672b81ebff/django_inline_actions-1.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e2232e4c394fe037e3ce075636282205", "sha256": "4527e1e6206b8d2368276ecd463e411fa6abf53871e185d86e237595cdb842f9" }, "downloads": -1, "filename": "django-inline-actions-1.1.0.tar.gz", "has_sig": false, "md5_digest": "e2232e4c394fe037e3ce075636282205", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11079, "upload_time": "2017-07-21T10:07:42", "url": "https://files.pythonhosted.org/packages/50/08/bdc1338066def98d014e8e0fd9ec2f9f0c9877ecdc22ef753c06f2f6ddc0/django-inline-actions-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "3b95bede52f5f2c135ecfea5730af6ba", "sha256": "fd31d3b4fb37dee55959f424eab66660f472c6d7d89ba26b049288c41727e3a0" }, "downloads": -1, "filename": "django_inline_actions-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "3b95bede52f5f2c135ecfea5730af6ba", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12190, "upload_time": "2018-01-04T21:36:33", "url": "https://files.pythonhosted.org/packages/30/7e/f40cd9a132f4930724fd4834aaf261a7d83d967ea98f4256ff22612de9d6/django_inline_actions-1.2.0-py2.py3-none-any.whl" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "271c94efe9ffb36907cae03e09d47d30", "sha256": "d2517b8cbf9087f4f6115583e579ec331e94fd6d8b5bbbf2db1620797c3f243a" }, "downloads": -1, "filename": "django_inline_actions-1.2.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "271c94efe9ffb36907cae03e09d47d30", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12200, "upload_time": "2018-02-09T13:17:45", "url": "https://files.pythonhosted.org/packages/41/da/2358ad83b363a45e4fb5ceb3ab9962f492bf63d99d7b8b8749d3c200dfb5/django_inline_actions-1.2.1-py2.py3-none-any.whl" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "06c35689c12c2966fe20f22118263215", "sha256": "1a62858842cf30d70926790643a655f6729acd29649f263701eaa2d9a75bc489" }, "downloads": -1, "filename": "django_inline_actions-1.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "06c35689c12c2966fe20f22118263215", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12196, "upload_time": "2018-02-09T14:36:49", "url": "https://files.pythonhosted.org/packages/80/1e/07f88e9f7ed11553f9775abbd37e9839d428a47d7148eccd44de52ca8ac7/django_inline_actions-1.3.0-py2.py3-none-any.whl" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "6ef035048b2eaf01ae729687b6c12d56", "sha256": "df68d106ec0c7afcb36179cc81e10eb743d10004980724fc5a79b3d9ed814c35" }, "downloads": -1, "filename": "django_inline_actions-2.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6ef035048b2eaf01ae729687b6c12d56", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12207, "upload_time": "2018-01-04T22:22:24", "url": "https://files.pythonhosted.org/packages/9e/dc/ba8409695ab521c18b9c39c09a83811c69f85ecd0823a4a614b814cabcff/django_inline_actions-2.0.0-py2.py3-none-any.whl" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "478844706e6b955875757a52ca23c596", "sha256": "e85242841b15ce6522e200abdc0dbcee21c63ae4c8b72e3610be27683fb5a769" }, "downloads": -1, "filename": "django_inline_actions-2.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "478844706e6b955875757a52ca23c596", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12215, "upload_time": "2018-01-20T12:31:01", "url": "https://files.pythonhosted.org/packages/6c/f5/44649b7a289fc16fc55f5abe2b2bf7e9cb9af6c0030b10e49d310e2e1b17/django_inline_actions-2.0.1-py2.py3-none-any.whl" } ], "2.0.2": [ { "comment_text": "", "digests": { "md5": "b14349ad954d92a3b7e4527219497b48", "sha256": "8ff5a84e639248e69a311707e54a5f0fdfec5fc85b989f25594be742314ea8a4" }, "downloads": -1, "filename": "django_inline_actions-2.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b14349ad954d92a3b7e4527219497b48", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 12183, "upload_time": "2018-04-12T21:30:20", "url": "https://files.pythonhosted.org/packages/f9/35/5a741b43eac81117b2550cf28b902db0d13ef9184e9e83207fba233c502c/django_inline_actions-2.0.2-py2.py3-none-any.whl" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "5bb79622bcbbaf708004192c22db2fdf", "sha256": "3f0860331bff62b34be822e8c0dc48180aa7e92b328d39542088d31aee617316" }, "downloads": -1, "filename": "django_inline_actions-2.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5bb79622bcbbaf708004192c22db2fdf", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 8012, "upload_time": "2018-09-09T15:59:16", "url": "https://files.pythonhosted.org/packages/be/35/4d0ee7b9e999a34d4890b8fcd2e490ebfd8757c2c173d152d76b01e44795/django_inline_actions-2.1.0-py2.py3-none-any.whl" } ], "2.2.0": [ { "comment_text": "", "digests": { "md5": "a7e312fadd7c870359b7126e7e06c41b", "sha256": "b4ae5a119de23a1d6820293fdda7a74b9cf22a3f34138cb9805c9f0ba08cbfb1" }, "downloads": -1, "filename": "django_inline_actions-2.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a7e312fadd7c870359b7126e7e06c41b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5,<4.0", "size": 18969, "upload_time": "2019-06-13T08:22:01", "url": "https://files.pythonhosted.org/packages/41/b7/137d23a0a47c5c2cf917e680d83cdc92ded82abb78ce5ad93184cb5b837e/django_inline_actions-2.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8878ad569970c5659d05345bd0719c22", "sha256": "ddd81026560b0f42cfa16ff54b59390308795dae0ccf4916abec0a575ac4d290" }, "downloads": -1, "filename": "django-inline-actions-2.2.0.tar.gz", "has_sig": false, "md5_digest": "8878ad569970c5659d05345bd0719c22", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5,<4.0", "size": 10804, "upload_time": "2019-06-13T08:21:59", "url": "https://files.pythonhosted.org/packages/9a/a7/b38c1488b02ae56522ac45f8eb8e0434dcafa1fc0f16de7c7fc7734cb732/django-inline-actions-2.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a7e312fadd7c870359b7126e7e06c41b", "sha256": "b4ae5a119de23a1d6820293fdda7a74b9cf22a3f34138cb9805c9f0ba08cbfb1" }, "downloads": -1, "filename": "django_inline_actions-2.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a7e312fadd7c870359b7126e7e06c41b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5,<4.0", "size": 18969, "upload_time": "2019-06-13T08:22:01", "url": "https://files.pythonhosted.org/packages/41/b7/137d23a0a47c5c2cf917e680d83cdc92ded82abb78ce5ad93184cb5b837e/django_inline_actions-2.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8878ad569970c5659d05345bd0719c22", "sha256": "ddd81026560b0f42cfa16ff54b59390308795dae0ccf4916abec0a575ac4d290" }, "downloads": -1, "filename": "django-inline-actions-2.2.0.tar.gz", "has_sig": false, "md5_digest": "8878ad569970c5659d05345bd0719c22", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5,<4.0", "size": 10804, "upload_time": "2019-06-13T08:21:59", "url": "https://files.pythonhosted.org/packages/9a/a7/b38c1488b02ae56522ac45f8eb8e0434dcafa1fc0f16de7c7fc7734cb732/django-inline-actions-2.2.0.tar.gz" } ] }