django-admin-action-forms


Namedjango-admin-action-forms JSON
Version 1.2.4 PyPI version JSON
download
home_pageNone
SummaryExtension for the Django admin panel that allows passing additional parameters to actions by creating intermediate pages with forms.
upload_time2024-11-27 21:13:39
maintainerMichał Pokusa
docs_urlNone
authorMichał Pokusa
requires_pythonNone
licenseMIT License Copyright (c) 2024 Michał Pokusa Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords django admin action actions form forms pass intermediate args arguments params parameters
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
# django-admin-action-forms

<p float="left">
    <a href="https://pypi.org/project/django-admin-action-forms/">
        <img src="https://img.shields.io/pypi/v/django-admin-action-forms?color=0073b7"/>
    </a>
    <a href="https://www.djangoproject.com/">
        <img src="https://img.shields.io/badge/3.2.x, 4.x.x, 5.x.x-a?style=flat&logo=django&label=django&labelColor=0c4b33&color=616161">
    </a>
</p>

Extension for the Django admin panel that allows passing additional parameters to actions by creating intermediate pages with forms.

- [🚀 Overview](#-overview)
- [🎉 Features](#-features)
- [🔌 Installation](#-installation)
- [✏️ Examples](#️examples)
  - [Simple confirm form](#simple-confirm-form)
  - [Action with parameters](#action-with-parameters)
  - [Customizing action form layout](#customizing-action-form-layout)
- [📄 Documentation](#-documentation)

## 🚀 Overview

Do you need confirmation pages for your actions in Django admin?<br>
Does creating multiple actions in Django admin that only differ in arguments sound familiar?<br>
Have you ever added a somewhat hacky way to pass additional parameters to an action?

**If so, this package is for you!**

This is how it looks in action:

<img src="https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/overview.gif" width="100%">

By adding a few lines of code, you can create actions with custom forms that will be displayed in an intermediate page before the action is executed. Data from the form will be passed to the action as an additional argument.

Simple and powerful!

### 🎉 Features

- Requires minimal configuration, easy to use
- Supports all modern Django versions (3.2.x, 4.x.x, 5.x.x)
- Built on top of Django's templates and forms, matches the Django admin style
- No additional dependencies
- Supports `fields`/`fieldsets`, `filter_horizontal`/`filter_vertical` and `autocomplete_fields`
- Works with custom widgets, validators and other Django form features
- Compatible with [django-no-queryset-admin-actions](https://pypi.org/project/django-no-queryset-admin-actions/)

## 🔌 Installation

1. Install using ``pip``:

    ```bash
    $ pip3 install django-admin-action-forms
    ```

2. Add `'django_admin_action_forms'` to your `INSTALLED_APPS` setting.
    ```python
    INSTALLED_APPS = [
        ...
        'django_admin_action_forms',
    ]
    ```

3. Include `'django_admin_action_forms.urls'` in your `urls.py` file. This is needed only if you want to use autocomplete.

    If you want to include them under the same path as admin site, make sure to place them **before** the admin URLs.

    ```python
    from django.contrib import admin
    from django.urls import path, include


    urlpatterns = [
        path("admin/action-forms/", include("django_admin_action_forms.urls")),
        path("admin/", admin.site.urls),
        ...
    ]
    ```
    ...or include them under any other path.

    ```python
    from django.contrib import admin
    from django.urls import path, include


    urlpatterns = [
        path("admin/", admin.site.urls),
        ...
        path("any/other/path/", include("django_admin_action_forms.urls")),
    ]
    ```

## ✏️ Examples

### Simple confirm form

Sometimes you do not need any additional parameters, but you want to display a confirmation form before executing the action, just to make sure the user is aware of what they are doing. By default, Django displays such form for the built-in `delete_selected` action.

Let's create a simple action that will reset the password for selected users, but before that, we want to display a confirmation form.

```python
from django_admin_action_forms import action_with_form, AdminActionForm


class ResetUsersPasswordActionForm(AdminActionForm):
    # No fields needed

    class Meta:
        list_objects = True
        help_text = "Are you sure you want proceed with this action?"


@action_with_form(
    ResetUsersPasswordActionForm,
    description="Reset password for selected users",
)
def reset_users_password_action(modeladmin, request, queryset, data):
    modeladmin.message_user(request, f"Password reset for {queryset.count()} users.")
```

By doing this, we recreated the behavior of intermediate page from the built-in `delete_selected` action.

<img src="https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/simple-confirm-form/reset-users-password.gif" width="100%">

### Action with parameters

In many cases however, you will want to pass additional parameters to the action. This can be very useful for e.g.:
- Changing the status of `Order` to one of the predefined values
- Setting a discount that you input for selected `Product` objects
- Adding multiple tags to selected `Article` objects at once
- Sending mails to selected `User` objects with a custom message, title and attachments

...and many more!

Let's create an action that will change the status of selected `Order` to a value that we select using a dropdown.

```python
from django import forms
from django_admin_action_forms import action_with_form, AdminActionForm


class ChangeOrderStatusActionForm(AdminActionForm):
    status = forms.ChoiceField(
        label="Status",
        choices=[("new", "New"), ("processing", "Processing"), ("completed", "Completed")],
        required=True,
    )


@action_with_form(
    ChangeOrderStatusActionForm,
    description="Change status for selected Orders",
)
def change_order_status_action(modeladmin, request, queryset, data):
    for order in queryset:
        order.status = data["status"]
        order.save()
    modeladmin.message_user(request, f'Status changed to {data["status"].upper()} for {queryset.count()} orders.')
```

<img src="https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/action-with-parameters/change-order-status.gif" width="100%">

You may think that this could be achieved by creating an action for each status, but what if you have 10 statuses? 100? This way you can create a single action that will work for all of them.

And how about parameter, that is not predefined, like a date or a number? It would be impossible to create an action for each possible value.

Let's create an action form that will accept a discount for selected `Products` and a date when the discount will end.

```python
from django import forms
from django_admin_action_forms import action_with_form, AdminActionForm


class SetProductDiscountActionForm(AdminActionForm):
    discount = forms.DecimalField(
        label="Discount (%)",
        min_value=0,
        max_value=100,
        decimal_places=2,
        required=True,
    )
    valid_until = forms.DateField(
        label="Valid until",
        required=True,
    )
```

<img src="https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/action-with-parameters/set-product-discount.gif" width="100%">

Now we can set any discount and any date, and because we subclassed [`AdminActionForm`](#adminactionform), we get a nice date picker.

### Customizing action form layout

If your form has many fields, you may want to group them into fieldsets or reorder them. You can do this by using the `fields`, `fieldsets`, or corresponding methods in `Meta`.

For `Model`-related fields, it might be useful to use `filter_horizontal`/`filter_vertical` or `autocomplete_fields`.

Let's create an action form for action that assigns selected `Tasks` to `Employee`, that we will select using autocomplete widget.
Also, let's add the field for setting the optional `Tags` for selected `Tasks`, and validate that no more than 3
are selected using <a href="https://docs.djangoproject.com/en/5.1/ref/forms/api/#using-forms-to-validate-data">Django's form validation</a>.

```python
from django import forms
from django_admin_action_forms import action_with_form, AdminActionForm


class AssignToEmployeeActionForm(AdminActionForm):
    employee = forms.ModelChoiceField(
        queryset=Employee.objects.all(),
        required=True,
    )
    tags = forms.ModelMultipleChoiceField(
        queryset=Tag.objects.all(),
        required=False,
    )

    def clean_tags(self):
        tags = self.cleaned_data["tags"]
        if tags.count() > 3:
            raise forms.ValidationError("You can't assign more than 3 tags to a task.")
        return tags

    class Meta:
        autocomplete_fields = ["employee"]
        filter_horizontal = ["tags"]
```

<img src="https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/customizing-action-form-layout/assign-to-employee.gif" width="100%">

## 📄 Documentation

#### <code>@action_with_form(<i>form_class, *, permissions=None, description=None</i>)</code>

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/actions/#the-action-decorator">
    <code>@admin.action</code>
</a>

Decorator that can be used instead of `@admin.action` to create action with custom form.
Functions decorated with `@action_with_form` should accept additional argument `data` that will contain cleaned data from the form, `permissions` and `description` work the same.

```python
@action_with_form(
    CustomActionForm,
    description="Description of the action",
)
def custom_action(self, request, queryset, data):
    value_of_field1 = data["field1"]
    optional_value_of_field2 = data.get("field2")
    ...
```

### ActionForm

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/forms/api/#django.forms.Form">
    <code>Form</code>
</a>

Base class for creating action forms responsible for all under the hood logic. Nearly always you will want to subclass `AdminActionForm` instead of `ActionForm`, as it provides additional features.

#### _def_ \_\_post_init\_\_(modeladmin, request, queryset)

> _Added in version 1.2.0_

Method called after the form is initialized that can be used to modify the form fields, add additional ones or change the form's `Meta` options based on the `modeladmin` from which the action was called, `request` and `queryset` containing objects on which the action will be performed.

```python
def __post_init__(self, modeladmin, request, queryset):
    modeladmin.message_user(
        request, f"Warning, this action cannot be undone.", "warning"
    )

    if request.user.is_superuser:
        self.fields["field1"].required = False

    if queryset.count() > 25:
        self.Meta.list_objects = False
```

### AdminActionForm

In addition to `ActionForm`, it replaces default widgets for most field types with corresponding Django admin widgets that e.g. add a interactive date picker or prepend a clickable link above URL fields.

Most of the time this is a class you want to subclass when creating custom action forms.

```python
class CustomActionForm(AdminActionForm):

    field1 = forms.ChoiceField(
        label="Field 1",
        choices=[(1, "Option 1"), (2, "Option 2"), (3, "Option 3")],
    )
    field2 = forms.CharField(
        label="Field 2",
        required=False,
        widget=forms.TextInput
    )
    field3 = forms.DateField(label="Field 3", initial="2024-07-15")

    ...
```

### ActionForm.Meta

> Works similar to some <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#modeladmin-options">
    <code>ModelAdmin</code> options
</a>

Additional configuration for action forms. It can be used to customize the layout of the form, add help text, or display a list of objects that will be affected by the action.

```python
class CustomActionForm(AdminActionForm):

    ...

    class Meta:
        list_objects = True
        help_text = "This is a help text"
        ...
```

Below you can find all available options:

#### list_objects

Default: `False`

If `True`, the intermediate page will display a list of objects that will be affected by the action similarly
to the intermediate page for built-in `delete_selected` action.

```python
list_objects = True
```

#### help_text

Default: `None`

Text displayed between the form and the list of objects or form in the intermediate page.

```python
help_text = "This text will be displayed between the form and the list of objects"
```

#### fields

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fields">
    <code>ModelAdmin.fields</code>
</a>

Default: `None`

Specifies the fields that should be displayed in the form. If `fieldsets` is provided, `fields` will be ignored.

```python
fields = ["field1", ("field2", "field3")]
```

#### _def_ get_fields(request)

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_fields">
    <code>ModelAdmin.get_fields()</code>
</a>

Method that can be used to dynamically determine fields that should be displayed in the form. Can be used to reorder, group or exclude fields based on the `request`. Should return a list of fields, as described above in the [`fields`](#fields).

```python
@classmethod
def get_fields(cls, request):
    if request.user.is_superuser:
        return ["field1", "field2", "field3"]
    else:
        return ["field1", "field2"]
```

#### fieldsets

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">
    <code>ModelAdmin.fieldsets</code>
</a>

Default: `None`

If both `fields` and `fieldsets` are provided, `fieldsets` will be used.

```python
fieldsets = [
    (
        None,
        {
            "fields": ["field1", "field2", ("field3", "field4")],
        },
    ),
    (
        "Fieldset 2",
        {
            "classes": ["collapse"],
            "fields": ["field5", ("field6", "field7")],
            "description": "This is a description for fieldset 2",
        },
    ),
]
```

#### _def_ get_fieldsets(request)

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_fieldsets">
    <code>ModelAdmin.get_fieldsets()</code>
</a>

Method that can be used to dynamically determine fieldsets that should be displayed in the form. Can be used to reorder, group or exclude fields based on the `request`. Should return a list of fieldsets, as described above in the [`fieldsets`](#fieldsets).

```python
@classmethod
def get_fieldsets(cls, request):
    if request.user.is_superuser:
        return [
            (
                None,
                {
                    "fields": ["field1", "field2", ("field3", "field4")],
                },
            ),
            (
                "Fieldset 2",
                {
                    "classes": ["collapse"],
                    "fields": ["field5", ("field6", "field7")],
                    "description": "This is a description for fieldset 2",
                },
            ),
        ]
    else:
        return [
            (
                None,
                {
                    "fields": ["field1", "field2", ("field3", "field4")],
                },
            ),
        ]
```

> [!NOTE]
> Only one of `get_fieldsets`, `fieldsets`, `get_fields` or `fields` should be defined in the `Meta` class.
> The order of precedence, from highest to lowest, is from left to right.

#### filter_horizontal

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_horizontal">
    <code>ModelAdmin.filter_horizontal</code>
</a>

Default: `None`

Sets fields that should use horizontal filter widget. It should be a list of field names.

```python
filter_horizontal = ["field1", "field2"]
```

#### filter_vertical

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_vertical">
    <code>ModelAdmin.filter_vertical</code>
</a>

Default: `None`

Sets fields that should use vertical filter widget. It should be a list of field names.

```python
filter_vertical = ["field1", "field2"]
```

#### autocomplete_fields

> Works similar to <a href="https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields">
    <code>ModelAdmin.autocomplete_fields</code>
</a>

Default: `None`

Sets fields that should use autocomplete widget. It should be a list of field names.

```python
autocomplete_fields = ["field1", "field2"]
```

> [!NOTE]
> Autocomplete requires including `'django_admin_action_forms.urls'` in your `urls.py` file.
> See [🔌 Installation](#-installation).

#### confirm_button_text

> _Added in version 1.2.0_

Default: `"Confirm"`

Text displayed on the confirm button. It can be either a `str` or a lazy translation.

```python
from django.utils.translation import gettext_lazy as _

confirm_button_text = _("Proceed")
```

#### cancel_button_text

> _Added in version 1.2.0_

Default: `"Cancel"`

Text displayed on the cancel button. It can be either a `str` or a lazy translation.

```python
from django.utils.translation import gettext_lazy as _

cancel_button_text = _("Abort")
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "django-admin-action-forms",
    "maintainer": "Micha\u0142 Pokusa",
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "django, admin, action, actions, form, forms, pass, intermediate, args, arguments, params, parameters",
    "author": "Micha\u0142 Pokusa",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/ed/10/dc03ef8bc2efa593cacf25e22c56b9d3a630d66077c4069635c4ea5f5d24/django_admin_action_forms-1.2.4.tar.gz",
    "platform": null,
    "description": "\n# django-admin-action-forms\n\n<p float=\"left\">\n    <a href=\"https://pypi.org/project/django-admin-action-forms/\">\n        <img src=\"https://img.shields.io/pypi/v/django-admin-action-forms?color=0073b7\"/>\n    </a>\n    <a href=\"https://www.djangoproject.com/\">\n        <img src=\"https://img.shields.io/badge/3.2.x, 4.x.x, 5.x.x-a?style=flat&logo=django&label=django&labelColor=0c4b33&color=616161\">\n    </a>\n</p>\n\nExtension for the Django admin panel that allows passing additional parameters to actions by creating intermediate pages with forms.\n\n- [\ud83d\ude80 Overview](#-overview)\n- [\ud83c\udf89 Features](#-features)\n- [\ud83d\udd0c Installation](#-installation)\n- [\u270f\ufe0f Examples](#\ufe0fexamples)\n  - [Simple confirm form](#simple-confirm-form)\n  - [Action with parameters](#action-with-parameters)\n  - [Customizing action form layout](#customizing-action-form-layout)\n- [\ud83d\udcc4 Documentation](#-documentation)\n\n## \ud83d\ude80 Overview\n\nDo you need confirmation pages for your actions in Django admin?<br>\nDoes creating multiple actions in Django admin that only differ in arguments sound familiar?<br>\nHave you ever added a somewhat hacky way to pass additional parameters to an action?\n\n**If so, this package is for you!**\n\nThis is how it looks in action:\n\n<img src=\"https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/overview.gif\" width=\"100%\">\n\nBy adding a few lines of code, you can create actions with custom forms that will be displayed in an intermediate page before the action is executed. Data from the form will be passed to the action as an additional argument.\n\nSimple and powerful!\n\n### \ud83c\udf89 Features\n\n- Requires minimal configuration, easy to use\n- Supports all modern Django versions (3.2.x, 4.x.x, 5.x.x)\n- Built on top of Django's templates and forms, matches the Django admin style\n- No additional dependencies\n- Supports `fields`/`fieldsets`, `filter_horizontal`/`filter_vertical` and `autocomplete_fields`\n- Works with custom widgets, validators and other Django form features\n- Compatible with [django-no-queryset-admin-actions](https://pypi.org/project/django-no-queryset-admin-actions/)\n\n## \ud83d\udd0c Installation\n\n1. Install using ``pip``:\n\n    ```bash\n    $ pip3 install django-admin-action-forms\n    ```\n\n2. Add `'django_admin_action_forms'` to your `INSTALLED_APPS` setting.\n    ```python\n    INSTALLED_APPS = [\n        ...\n        'django_admin_action_forms',\n    ]\n    ```\n\n3. Include `'django_admin_action_forms.urls'` in your `urls.py` file. This is needed only if you want to use autocomplete.\n\n    If you want to include them under the same path as admin site, make sure to place them **before** the admin URLs.\n\n    ```python\n    from django.contrib import admin\n    from django.urls import path, include\n\n\n    urlpatterns = [\n        path(\"admin/action-forms/\", include(\"django_admin_action_forms.urls\")),\n        path(\"admin/\", admin.site.urls),\n        ...\n    ]\n    ```\n    ...or include them under any other path.\n\n    ```python\n    from django.contrib import admin\n    from django.urls import path, include\n\n\n    urlpatterns = [\n        path(\"admin/\", admin.site.urls),\n        ...\n        path(\"any/other/path/\", include(\"django_admin_action_forms.urls\")),\n    ]\n    ```\n\n## \u270f\ufe0f Examples\n\n### Simple confirm form\n\nSometimes you do not need any additional parameters, but you want to display a confirmation form before executing the action, just to make sure the user is aware of what they are doing. By default, Django displays such form for the built-in `delete_selected` action.\n\nLet's create a simple action that will reset the password for selected users, but before that, we want to display a confirmation form.\n\n```python\nfrom django_admin_action_forms import action_with_form, AdminActionForm\n\n\nclass ResetUsersPasswordActionForm(AdminActionForm):\n    # No fields needed\n\n    class Meta:\n        list_objects = True\n        help_text = \"Are you sure you want proceed with this action?\"\n\n\n@action_with_form(\n    ResetUsersPasswordActionForm,\n    description=\"Reset password for selected users\",\n)\ndef reset_users_password_action(modeladmin, request, queryset, data):\n    modeladmin.message_user(request, f\"Password reset for {queryset.count()} users.\")\n```\n\nBy doing this, we recreated the behavior of intermediate page from the built-in `delete_selected` action.\n\n<img src=\"https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/simple-confirm-form/reset-users-password.gif\" width=\"100%\">\n\n### Action with parameters\n\nIn many cases however, you will want to pass additional parameters to the action. This can be very useful for e.g.:\n- Changing the status of `Order` to one of the predefined values\n- Setting a discount that you input for selected `Product` objects\n- Adding multiple tags to selected `Article` objects at once\n- Sending mails to selected `User` objects with a custom message, title and attachments\n\n...and many more!\n\nLet's create an action that will change the status of selected `Order` to a value that we select using a dropdown.\n\n```python\nfrom django import forms\nfrom django_admin_action_forms import action_with_form, AdminActionForm\n\n\nclass ChangeOrderStatusActionForm(AdminActionForm):\n    status = forms.ChoiceField(\n        label=\"Status\",\n        choices=[(\"new\", \"New\"), (\"processing\", \"Processing\"), (\"completed\", \"Completed\")],\n        required=True,\n    )\n\n\n@action_with_form(\n    ChangeOrderStatusActionForm,\n    description=\"Change status for selected Orders\",\n)\ndef change_order_status_action(modeladmin, request, queryset, data):\n    for order in queryset:\n        order.status = data[\"status\"]\n        order.save()\n    modeladmin.message_user(request, f'Status changed to {data[\"status\"].upper()} for {queryset.count()} orders.')\n```\n\n<img src=\"https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/action-with-parameters/change-order-status.gif\" width=\"100%\">\n\nYou may think that this could be achieved by creating an action for each status, but what if you have 10 statuses? 100? This way you can create a single action that will work for all of them.\n\nAnd how about parameter, that is not predefined, like a date or a number? It would be impossible to create an action for each possible value.\n\nLet's create an action form that will accept a discount for selected `Products` and a date when the discount will end.\n\n```python\nfrom django import forms\nfrom django_admin_action_forms import action_with_form, AdminActionForm\n\n\nclass SetProductDiscountActionForm(AdminActionForm):\n    discount = forms.DecimalField(\n        label=\"Discount (%)\",\n        min_value=0,\n        max_value=100,\n        decimal_places=2,\n        required=True,\n    )\n    valid_until = forms.DateField(\n        label=\"Valid until\",\n        required=True,\n    )\n```\n\n<img src=\"https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/action-with-parameters/set-product-discount.gif\" width=\"100%\">\n\nNow we can set any discount and any date, and because we subclassed [`AdminActionForm`](#adminactionform), we get a nice date picker.\n\n### Customizing action form layout\n\nIf your form has many fields, you may want to group them into fieldsets or reorder them. You can do this by using the `fields`, `fieldsets`, or corresponding methods in `Meta`.\n\nFor `Model`-related fields, it might be useful to use `filter_horizontal`/`filter_vertical` or `autocomplete_fields`.\n\nLet's create an action form for action that assigns selected `Tasks` to `Employee`, that we will select using autocomplete widget.\nAlso, let's add the field for setting the optional `Tags` for selected `Tasks`, and validate that no more than 3\nare selected using <a href=\"https://docs.djangoproject.com/en/5.1/ref/forms/api/#using-forms-to-validate-data\">Django's form validation</a>.\n\n```python\nfrom django import forms\nfrom django_admin_action_forms import action_with_form, AdminActionForm\n\n\nclass AssignToEmployeeActionForm(AdminActionForm):\n    employee = forms.ModelChoiceField(\n        queryset=Employee.objects.all(),\n        required=True,\n    )\n    tags = forms.ModelMultipleChoiceField(\n        queryset=Tag.objects.all(),\n        required=False,\n    )\n\n    def clean_tags(self):\n        tags = self.cleaned_data[\"tags\"]\n        if tags.count() > 3:\n            raise forms.ValidationError(\"You can't assign more than 3 tags to a task.\")\n        return tags\n\n    class Meta:\n        autocomplete_fields = [\"employee\"]\n        filter_horizontal = [\"tags\"]\n```\n\n<img src=\"https://raw.githubusercontent.com/michalpokusa/django-admin-action-forms/main/resources/examples/customizing-action-form-layout/assign-to-employee.gif\" width=\"100%\">\n\n## \ud83d\udcc4 Documentation\n\n#### <code>@action_with_form(<i>form_class, *, permissions=None, description=None</i>)</code>\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/actions/#the-action-decorator\">\n    <code>@admin.action</code>\n</a>\n\nDecorator that can be used instead of `@admin.action` to create action with custom form.\nFunctions decorated with `@action_with_form` should accept additional argument `data` that will contain cleaned data from the form, `permissions` and `description` work the same.\n\n```python\n@action_with_form(\n    CustomActionForm,\n    description=\"Description of the action\",\n)\ndef custom_action(self, request, queryset, data):\n    value_of_field1 = data[\"field1\"]\n    optional_value_of_field2 = data.get(\"field2\")\n    ...\n```\n\n### ActionForm\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/forms/api/#django.forms.Form\">\n    <code>Form</code>\n</a>\n\nBase class for creating action forms responsible for all under the hood logic. Nearly always you will want to subclass `AdminActionForm` instead of `ActionForm`, as it provides additional features.\n\n#### _def_ \\_\\_post_init\\_\\_(modeladmin, request, queryset)\n\n> _Added in version 1.2.0_\n\nMethod called after the form is initialized that can be used to modify the form fields, add additional ones or change the form's `Meta` options based on the `modeladmin` from which the action was called, `request` and `queryset` containing objects on which the action will be performed.\n\n```python\ndef __post_init__(self, modeladmin, request, queryset):\n    modeladmin.message_user(\n        request, f\"Warning, this action cannot be undone.\", \"warning\"\n    )\n\n    if request.user.is_superuser:\n        self.fields[\"field1\"].required = False\n\n    if queryset.count() > 25:\n        self.Meta.list_objects = False\n```\n\n### AdminActionForm\n\nIn addition to `ActionForm`, it replaces default widgets for most field types with corresponding Django admin widgets that e.g. add a interactive date picker or prepend a clickable link above URL fields.\n\nMost of the time this is a class you want to subclass when creating custom action forms.\n\n```python\nclass CustomActionForm(AdminActionForm):\n\n    field1 = forms.ChoiceField(\n        label=\"Field 1\",\n        choices=[(1, \"Option 1\"), (2, \"Option 2\"), (3, \"Option 3\")],\n    )\n    field2 = forms.CharField(\n        label=\"Field 2\",\n        required=False,\n        widget=forms.TextInput\n    )\n    field3 = forms.DateField(label=\"Field 3\", initial=\"2024-07-15\")\n\n    ...\n```\n\n### ActionForm.Meta\n\n> Works similar to some <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#modeladmin-options\">\n    <code>ModelAdmin</code> options\n</a>\n\nAdditional configuration for action forms. It can be used to customize the layout of the form, add help text, or display a list of objects that will be affected by the action.\n\n```python\nclass CustomActionForm(AdminActionForm):\n\n    ...\n\n    class Meta:\n        list_objects = True\n        help_text = \"This is a help text\"\n        ...\n```\n\nBelow you can find all available options:\n\n#### list_objects\n\nDefault: `False`\n\nIf `True`, the intermediate page will display a list of objects that will be affected by the action similarly\nto the intermediate page for built-in `delete_selected` action.\n\n```python\nlist_objects = True\n```\n\n#### help_text\n\nDefault: `None`\n\nText displayed between the form and the list of objects or form in the intermediate page.\n\n```python\nhelp_text = \"This text will be displayed between the form and the list of objects\"\n```\n\n#### fields\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fields\">\n    <code>ModelAdmin.fields</code>\n</a>\n\nDefault: `None`\n\nSpecifies the fields that should be displayed in the form. If `fieldsets` is provided, `fields` will be ignored.\n\n```python\nfields = [\"field1\", (\"field2\", \"field3\")]\n```\n\n#### _def_ get_fields(request)\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_fields\">\n    <code>ModelAdmin.get_fields()</code>\n</a>\n\nMethod that can be used to dynamically determine fields that should be displayed in the form. Can be used to reorder, group or exclude fields based on the `request`. Should return a list of fields, as described above in the [`fields`](#fields).\n\n```python\n@classmethod\ndef get_fields(cls, request):\n    if request.user.is_superuser:\n        return [\"field1\", \"field2\", \"field3\"]\n    else:\n        return [\"field1\", \"field2\"]\n```\n\n#### fieldsets\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets\">\n    <code>ModelAdmin.fieldsets</code>\n</a>\n\nDefault: `None`\n\nIf both `fields` and `fieldsets` are provided, `fieldsets` will be used.\n\n```python\nfieldsets = [\n    (\n        None,\n        {\n            \"fields\": [\"field1\", \"field2\", (\"field3\", \"field4\")],\n        },\n    ),\n    (\n        \"Fieldset 2\",\n        {\n            \"classes\": [\"collapse\"],\n            \"fields\": [\"field5\", (\"field6\", \"field7\")],\n            \"description\": \"This is a description for fieldset 2\",\n        },\n    ),\n]\n```\n\n#### _def_ get_fieldsets(request)\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_fieldsets\">\n    <code>ModelAdmin.get_fieldsets()</code>\n</a>\n\nMethod that can be used to dynamically determine fieldsets that should be displayed in the form. Can be used to reorder, group or exclude fields based on the `request`. Should return a list of fieldsets, as described above in the [`fieldsets`](#fieldsets).\n\n```python\n@classmethod\ndef get_fieldsets(cls, request):\n    if request.user.is_superuser:\n        return [\n            (\n                None,\n                {\n                    \"fields\": [\"field1\", \"field2\", (\"field3\", \"field4\")],\n                },\n            ),\n            (\n                \"Fieldset 2\",\n                {\n                    \"classes\": [\"collapse\"],\n                    \"fields\": [\"field5\", (\"field6\", \"field7\")],\n                    \"description\": \"This is a description for fieldset 2\",\n                },\n            ),\n        ]\n    else:\n        return [\n            (\n                None,\n                {\n                    \"fields\": [\"field1\", \"field2\", (\"field3\", \"field4\")],\n                },\n            ),\n        ]\n```\n\n> [!NOTE]\n> Only one of `get_fieldsets`, `fieldsets`, `get_fields` or `fields` should be defined in the `Meta` class.\n> The order of precedence, from highest to lowest, is from left to right.\n\n#### filter_horizontal\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_horizontal\">\n    <code>ModelAdmin.filter_horizontal</code>\n</a>\n\nDefault: `None`\n\nSets fields that should use horizontal filter widget. It should be a list of field names.\n\n```python\nfilter_horizontal = [\"field1\", \"field2\"]\n```\n\n#### filter_vertical\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_vertical\">\n    <code>ModelAdmin.filter_vertical</code>\n</a>\n\nDefault: `None`\n\nSets fields that should use vertical filter widget. It should be a list of field names.\n\n```python\nfilter_vertical = [\"field1\", \"field2\"]\n```\n\n#### autocomplete_fields\n\n> Works similar to <a href=\"https://docs.djangoproject.com/en/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields\">\n    <code>ModelAdmin.autocomplete_fields</code>\n</a>\n\nDefault: `None`\n\nSets fields that should use autocomplete widget. It should be a list of field names.\n\n```python\nautocomplete_fields = [\"field1\", \"field2\"]\n```\n\n> [!NOTE]\n> Autocomplete requires including `'django_admin_action_forms.urls'` in your `urls.py` file.\n> See [\ud83d\udd0c Installation](#-installation).\n\n#### confirm_button_text\n\n> _Added in version 1.2.0_\n\nDefault: `\"Confirm\"`\n\nText displayed on the confirm button. It can be either a `str` or a lazy translation.\n\n```python\nfrom django.utils.translation import gettext_lazy as _\n\nconfirm_button_text = _(\"Proceed\")\n```\n\n#### cancel_button_text\n\n> _Added in version 1.2.0_\n\nDefault: `\"Cancel\"`\n\nText displayed on the cancel button. It can be either a `str` or a lazy translation.\n\n```python\nfrom django.utils.translation import gettext_lazy as _\n\ncancel_button_text = _(\"Abort\")\n```\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2024 Micha\u0142 Pokusa  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Extension for the Django admin panel that allows passing additional parameters to actions by creating intermediate pages with forms.",
    "version": "1.2.4",
    "project_urls": {
        "Repository": "https://github.com/michalpokusa/django-admin-action-forms"
    },
    "split_keywords": [
        "django",
        " admin",
        " action",
        " actions",
        " form",
        " forms",
        " pass",
        " intermediate",
        " args",
        " arguments",
        " params",
        " parameters"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9c9406348bbbf90a673af88b2d1235ef3e4bee35cb70bd64c038c6d4478477c4",
                "md5": "52f4cc670451122d4ea50fc61cfc4aa7",
                "sha256": "18369729cbe962d4876fb89e1d96715ccb1ce20a0dd8b210cb138cbbc4766f56"
            },
            "downloads": -1,
            "filename": "django_admin_action_forms-1.2.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "52f4cc670451122d4ea50fc61cfc4aa7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 25124,
            "upload_time": "2024-11-27T21:13:38",
            "upload_time_iso_8601": "2024-11-27T21:13:38.256925Z",
            "url": "https://files.pythonhosted.org/packages/9c/94/06348bbbf90a673af88b2d1235ef3e4bee35cb70bd64c038c6d4478477c4/django_admin_action_forms-1.2.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ed10dc03ef8bc2efa593cacf25e22c56b9d3a630d66077c4069635c4ea5f5d24",
                "md5": "a9162971f59b8f560baaf765d48fb4eb",
                "sha256": "81eb69cf5e192ea9c03ca37999a5972a6d30168869bb2f9033d9e8faa8f3574d"
            },
            "downloads": -1,
            "filename": "django_admin_action_forms-1.2.4.tar.gz",
            "has_sig": false,
            "md5_digest": "a9162971f59b8f560baaf765d48fb4eb",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 3773302,
            "upload_time": "2024-11-27T21:13:39",
            "upload_time_iso_8601": "2024-11-27T21:13:39.273876Z",
            "url": "https://files.pythonhosted.org/packages/ed/10/dc03ef8bc2efa593cacf25e22c56b9d3a630d66077c4069635c4ea5f5d24/django_admin_action_forms-1.2.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-27 21:13:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "michalpokusa",
    "github_project": "django-admin-action-forms",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "django-admin-action-forms"
}
        
Elapsed time: 0.40834s