From 0e75b3182be8c288e556e77bdc4707f81d8eae85 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Tue, 8 Apr 2025 12:48:26 +0200 Subject: [PATCH 01/14] parameterize namespace --- django_adminlink/admin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 0fbf496..887c659 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -7,6 +7,7 @@ class LinkFieldAdminMixin: admin_site_to_link = None + admin_url_namespace = 'admin' def _convert_list_display_item(self, field_name): if isinstance(field_name, str): @@ -32,7 +33,10 @@ def _link_to_model_field(self, field): admin_site = self.admin_site_to_link or admin.site model_admin = admin_site._registry.get(related_model) if model_admin is not None: - url_root = f"admin:{related_model._meta.app_label}_{related_model._meta.model_name}_change" + url_root = f"related_model._meta.app_label}_{related_model._meta.model_name}_change" + if self.admin_url_namespace: + # prefix with namespace + url_root = f'{self.admin_url_namespace}:{url_root}' @admin.display(description=field.name, ordering=f"{field.name}") def column_render(obj): From 661aa6cbca77bb476392f9411634b0d60790fc5d Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Tue, 8 Apr 2025 12:50:16 +0200 Subject: [PATCH 02/14] formatting --- django_adminlink/admin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 887c659..8583044 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -7,7 +7,7 @@ class LinkFieldAdminMixin: admin_site_to_link = None - admin_url_namespace = 'admin' + admin_url_namespace = "admin" def _convert_list_display_item(self, field_name): if isinstance(field_name, str): @@ -33,10 +33,10 @@ def _link_to_model_field(self, field): admin_site = self.admin_site_to_link or admin.site model_admin = admin_site._registry.get(related_model) if model_admin is not None: - url_root = f"related_model._meta.app_label}_{related_model._meta.model_name}_change" + url_root = f"{related_model._meta.app_label}_{related_model._meta.model_name}_change" if self.admin_url_namespace: # prefix with namespace - url_root = f'{self.admin_url_namespace}:{url_root}' + url_root = f"{self.admin_url_namespace}:{url_root}" @admin.display(description=field.name, ordering=f"{field.name}") def column_render(obj): From 57019a6efe8654711a19033b7a4bd7cdcace4ab0 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 00:25:31 +0200 Subject: [PATCH 03/14] admin action buttons --- django_adminlink/admin.py | 26 ++++++++++++++++++- .../static/js/single_admin_action.js | 9 +++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 django_adminlink/static/js/single_admin_action.js diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 8583044..3d42f96 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -2,7 +2,9 @@ from django.core.exceptions import FieldDoesNotExist from django.db import models from django.urls import reverse -from django.utils.html import format_html +from django.utils.html import format_html_join +from django.forms import Media +import json class LinkFieldAdminMixin: @@ -57,3 +59,25 @@ def column_render(obj): class LinkFieldAdmin(LinkFieldAdminMixin, admin.ModelAdmin): pass + + +class SingleItemActionMixin: + action_buttons = [] + + @admin.display(description="actions") + def action_button_column(self, obj): + if isinstance(self.action_buttons, dict): + action_buttons = self.action_buttons.items() + else: + action_buttons = [(x, x) for x in self.action_buttons] + return format_html_join( + '', + '', + [(json.dumps(item), json.dumps(str(obj.pk)), label) + for label, item in action_buttons] + ) + + + @property + def media(self): + return super().media + Media(js=['/static/js/single_admin_action.js']) diff --git a/django_adminlink/static/js/single_admin_action.js b/django_adminlink/static/js/single_admin_action.js new file mode 100644 index 0000000..b05c72f --- /dev/null +++ b/django_adminlink/static/js/single_admin_action.js @@ -0,0 +1,9 @@ +function get_checkboxes(action, pk) { + document.querySelector(`select[name=action]`).value = action; + for(const item of document.querySelectorAll('input.action-select[type=checkbox]')) { + item.checked = false; + } + const item = document.querySelector(`input.action-select[type=checkbox][value="${pk}"]`); + item.checked = true; + item.form.submit(); +} \ No newline at end of file From 5e3d7b555f018a05a17807cc5891f7dc632818b9 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 00:26:49 +0200 Subject: [PATCH 04/14] admin action buttons --- django_adminlink/admin.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 3d42f96..96ce7cc 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -1,10 +1,11 @@ +import json + from django.contrib import admin from django.core.exceptions import FieldDoesNotExist from django.db import models +from django.forms import Media from django.urls import reverse from django.utils.html import format_html_join -from django.forms import Media -import json class LinkFieldAdminMixin: @@ -71,13 +72,17 @@ def action_button_column(self, obj): else: action_buttons = [(x, x) for x in self.action_buttons] return format_html_join( - '', + "", '', - [(json.dumps(item), json.dumps(str(obj.pk)), label) - for label, item in action_buttons] + [ + (json.dumps(item), json.dumps(str(obj.pk)), label) + for label, item in action_buttons + ], ) + def get_list_display(self, request): + return [*super().get_list_display(request), self.action_button_column] @property def media(self): - return super().media + Media(js=['/static/js/single_admin_action.js']) + return super().media + Media(js=["/static/js/single_admin_action.js"]) From e40211f0db8a259876fd42a3a2f78c518fbd8869 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 00:42:01 +0200 Subject: [PATCH 05/14] admin action buttons --- django_adminlink/admin.py | 9 ++------- django_adminlink/static/js/single_admin_action.js | 13 +++++++++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 96ce7cc..1c4ce50 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -1,5 +1,3 @@ -import json - from django.contrib import admin from django.core.exceptions import FieldDoesNotExist from django.db import models @@ -73,11 +71,8 @@ def action_button_column(self, obj): action_buttons = [(x, x) for x in self.action_buttons] return format_html_join( "", - '', - [ - (json.dumps(item), json.dumps(str(obj.pk)), label) - for label, item in action_buttons - ], + '', + [(item, str(obj.pk), label) for label, item in action_buttons], ) def get_list_display(self, request): diff --git a/django_adminlink/static/js/single_admin_action.js b/django_adminlink/static/js/single_admin_action.js index b05c72f..91aff3c 100644 --- a/django_adminlink/static/js/single_admin_action.js +++ b/django_adminlink/static/js/single_admin_action.js @@ -1,9 +1,18 @@ -function get_checkboxes(action, pk) { - document.querySelector(`select[name=action]`).value = action; +function get_checkboxes(e) { + const pk = e.getAttribute('data-pk'); + const action = e.getAttribute('data-action'); + const actionSelector = document.querySelector(`select[name=action]`); + if(actionSelector == null) { + return; + } + actionSelector.value = action; for(const item of document.querySelectorAll('input.action-select[type=checkbox]')) { item.checked = false; } const item = document.querySelector(`input.action-select[type=checkbox][value="${pk}"]`); + if(item == null) { + return; + } item.checked = true; item.form.submit(); } \ No newline at end of file From 55c04fcf6d7fc5dc2041451e3d68f7ff4e840df6 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 15:04:33 +0200 Subject: [PATCH 06/14] disable acrossinput and add customized themes per action button --- django_adminlink/admin.py | 14 ++++++++++---- django_adminlink/static/js/single_admin_action.js | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 1c4ce50..09acaa6 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -71,13 +71,19 @@ def action_button_column(self, obj): action_buttons = [(x, x) for x in self.action_buttons] return format_html_join( "", - '', - [(item, str(obj.pk), label) for label, item in action_buttons], + '', + [(item, item, str(obj.pk), label) + for label, item in action_buttons], ) def get_list_display(self, request): - return [*super().get_list_display(request), self.action_button_column] + items = super().get_list_display(request) + if self.action_buttons: + return [*items, self.action_button_column] + else: + # if no action buttons are used, we can simply drop the column + return items @property def media(self): - return super().media + Media(js=["/static/js/single_admin_action.js"]) + return super().media + Media(js=["js/single_admin_action.js"]) diff --git a/django_adminlink/static/js/single_admin_action.js b/django_adminlink/static/js/single_admin_action.js index 91aff3c..08492bc 100644 --- a/django_adminlink/static/js/single_admin_action.js +++ b/django_adminlink/static/js/single_admin_action.js @@ -5,6 +5,9 @@ function get_checkboxes(e) { if(actionSelector == null) { return; } + for(const acrossInput of document.querySelectorAll('div.actions input.select-across')) { + acrossInput.value = 0; + } actionSelector.value = action; for(const item of document.querySelectorAll('input.action-select[type=checkbox]')) { item.checked = false; From 9a4577a797eee142d75420bacad1d19a42cefcba Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 15:09:32 +0200 Subject: [PATCH 07/14] black --- django_adminlink/admin.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 09acaa6..0cb64b8 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -72,8 +72,7 @@ def action_button_column(self, obj): return format_html_join( "", '', - [(item, item, str(obj.pk), label) - for label, item in action_buttons], + [(item, item, str(obj.pk), label) for label, item in action_buttons], ) def get_list_display(self, request): From 9860fe6de47db6f937d45d5c27c67f36915f8269 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 15:26:20 +0200 Subject: [PATCH 08/14] updated readme --- README.md | 38 +++++++++++++++++++++++++++++++++++++- django_adminlink/admin.py | 4 ++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 179b32a..5d3cc82 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ The Django admin allows to list rows in an easy way. Some feature that seems to be "missing" is to jump in an efficient way to the detail view of a *related* object. For example if a model `A` has a `ForeignKey` to `B`, then the `ModelAdmin` of `A` can show the `__str__` of `B`, but without a link. +Django's admin actions are also very useful, but what seems to be missing is an easy way to just run the action on a single row without too much "hassle". + This package provides a mixin to effectively add such links. ## Installation @@ -19,7 +21,11 @@ pip install django-adminlink ## Usage -Once the package is installed, you can use the `LinkFieldAdminMixin` mixin in the admins where you want `ForeignKey`s and `OneToOneField`s to be linked to the corresponding admin detail view of that object: +Once the package is installed, we can work with the mixins provided by the package. + +### Adding links to `ForeignKey` fields + +you can use the `LinkFieldAdminMixin` mixin in the admins where you want `ForeignKey`s and `OneToOneField`s to be linked to the corresponding admin detail view of that object: ```python3 from django.contrib import admin @@ -32,3 +38,33 @@ class MovieAdmin(LinkFieldAdminMixin, admin.ModelAdmin): ``` If `genre` is a `ForeignKey` to a `Genre` model for example, and `Genre` has its own `ModelAdmin`, it will automatically convert `genre` into a column that adds a link to the admin detail view of the corresponding genre. + +### Single row actions + +The package also provides a `SingleItemActionMixin`, this enables to add a column at the right end of the admin that contains (one or more) buttons. These buttons then run a Django admin action on a *single* record. + +One can specify which actions to run by listing these, for example: + +```python3 +from django.contrib import admin +from django_adminlink.admin import SingleItemActionMixin + +@admin.register(Movie) +class MovieAdmin(SingleItemActionMixin, admin.ModelAdmin): + action_buttons = {'delete': 'delete_selected'} +``` + +One can work with a dictionary that has as key the "label" of the button, and as value the name (key) of the action to work with. This will add a button with the label "delete" as last column. When clicked, that row, and only that row is then removed. + +The package does not perform the action itself: it works with a small amount of *JavaScript* that just disables all checkboxes, enables the one of the selected row, and finally submits the action form, and lets Django handle the logic further. + +If the label(s) and action(s) are the same, one can also work with a list of the names of the actions, like: + +```python3 +from django.contrib import admin +from django_adminlink.admin import SingleItemActionMixin + +@admin.register(Movie) +class MovieAdmin(SingleItemActionMixin, admin.ModelAdmin): + action_buttons = ['delete_selected'] +``` \ No newline at end of file diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 0cb64b8..ae36a75 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -86,3 +86,7 @@ def get_list_display(self, request): @property def media(self): return super().media + Media(js=["js/single_admin_action.js"]) + + +class SingleItemActionAdmin(SingleItemActionMixin, admin.ModelAdmin): + pass From 90895ad2e9a30f57fa44b5aab9e0ce12b72c253c Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sat, 26 Apr 2025 13:27:35 +0000 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`f?= =?UTF-8?q?eature/parameterize-namespace`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @KommuSoft. * https://github.com/hapytex/django-adminlink/pull/1#issuecomment-2786028575 The following files were modified: * `django_adminlink/admin.py` * `django_adminlink/static/js/single_admin_action.js` --- django_adminlink/admin.py | 37 +++++++++++++++++++ .../static/js/single_admin_action.js | 7 ++++ 2 files changed, 44 insertions(+) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index ae36a75..50054f2 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -11,6 +11,11 @@ class LinkFieldAdminMixin: admin_url_namespace = "admin" def _convert_list_display_item(self, field_name): + """ + Converts a list display field name to a callable that renders a link for ForeignKey fields. + + If the specified field is a ForeignKey, returns a callable that displays the related object as a clickable link to its admin change page. Otherwise, returns the original field name. + """ if isinstance(field_name, str): try: field = self.model._meta.get_field(field_name) @@ -30,6 +35,11 @@ def get_list_display(self, request): return result def _link_to_model_field(self, field): + """ + Returns a callable that renders a ForeignKey field as a clickable link to the related object's admin change page. + + If the related model is not registered with the admin site, returns the field name instead. + """ related_model = field.related_model admin_site = self.admin_site_to_link or admin.site model_admin = admin_site._registry.get(related_model) @@ -41,6 +51,15 @@ def _link_to_model_field(self, field): @admin.display(description=field.name, ordering=f"{field.name}") def column_render(obj): + """ + Renders a foreign key field as a clickable link to the related object's admin change page. + + Args: + obj: The model instance containing the foreign key field. + + Returns: + An HTML anchor element linking to the related object's admin page, or None if the field is not set. + """ key = getattr(obj, field.name) if key is not None: return format_html( @@ -65,6 +84,12 @@ class SingleItemActionMixin: @admin.display(description="actions") def action_button_column(self, obj): + """ + Renders action buttons for each object in the admin list display. + + Each button is configured with data attributes for the action name and object primary key, + and triggers the `get_checkboxes` JavaScript function when clicked. + """ if isinstance(self.action_buttons, dict): action_buttons = self.action_buttons.items() else: @@ -76,6 +101,12 @@ def action_button_column(self, obj): ) def get_list_display(self, request): + """ + Extends the list display to include a column of action buttons if any are defined. + + If the `action_buttons` attribute is set, appends the `action_button_column` to the list + display; otherwise, returns the default list display. + """ items = super().get_list_display(request) if self.action_buttons: return [*items, self.action_button_column] @@ -85,6 +116,12 @@ def get_list_display(self, request): @property def media(self): + """ + Extends the admin media to include JavaScript for single-item action buttons. + + Returns: + The combined media object with the additional JavaScript file included. + """ return super().media + Media(js=["js/single_admin_action.js"]) diff --git a/django_adminlink/static/js/single_admin_action.js b/django_adminlink/static/js/single_admin_action.js index 08492bc..0b3ee17 100644 --- a/django_adminlink/static/js/single_admin_action.js +++ b/django_adminlink/static/js/single_admin_action.js @@ -1,3 +1,10 @@ +/** + * Selects a single item in a Django admin list and triggers the specified admin action for that item. + * + * Retrieves the primary key and action from the provided element's data attributes, updates the action selector, unchecks all other items, checks the targeted item, and submits the form to perform the action on that item only. + * + * @param {Element} e - The element containing `data-pk` and `data-action` attributes for the target item and action. + */ function get_checkboxes(e) { const pk = e.getAttribute('data-pk'); const action = e.getAttribute('data-action'); From c984f28268ac83249bf0e69ff5ffa6ccd4451138 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 15:44:22 +0200 Subject: [PATCH 10/14] black --- django_adminlink/admin.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 50054f2..08a0b4a 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -13,7 +13,7 @@ class LinkFieldAdminMixin: def _convert_list_display_item(self, field_name): """ Converts a list display field name to a callable that renders a link for ForeignKey fields. - + If the specified field is a ForeignKey, returns a callable that displays the related object as a clickable link to its admin change page. Otherwise, returns the original field name. """ if isinstance(field_name, str): @@ -37,7 +37,7 @@ def get_list_display(self, request): def _link_to_model_field(self, field): """ Returns a callable that renders a ForeignKey field as a clickable link to the related object's admin change page. - + If the related model is not registered with the admin site, returns the field name instead. """ related_model = field.related_model @@ -53,10 +53,10 @@ def _link_to_model_field(self, field): def column_render(obj): """ Renders a foreign key field as a clickable link to the related object's admin change page. - + Args: obj: The model instance containing the foreign key field. - + Returns: An HTML anchor element linking to the related object's admin page, or None if the field is not set. """ @@ -86,7 +86,7 @@ class SingleItemActionMixin: def action_button_column(self, obj): """ Renders action buttons for each object in the admin list display. - + Each button is configured with data attributes for the action name and object primary key, and triggers the `get_checkboxes` JavaScript function when clicked. """ @@ -103,7 +103,7 @@ def action_button_column(self, obj): def get_list_display(self, request): """ Extends the list display to include a column of action buttons if any are defined. - + If the `action_buttons` attribute is set, appends the `action_button_column` to the list display; otherwise, returns the default list display. """ @@ -118,7 +118,7 @@ def get_list_display(self, request): def media(self): """ Extends the admin media to include JavaScript for single-item action buttons. - + Returns: The combined media object with the additional JavaScript file included. """ From 9c7bc8a5baf8e0a5eaa65eaef52f37d1ad912a62 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 15:45:12 +0200 Subject: [PATCH 11/14] black --- django_adminlink/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_adminlink/admin.py b/django_adminlink/admin.py index 08a0b4a..b4f53ef 100644 --- a/django_adminlink/admin.py +++ b/django_adminlink/admin.py @@ -3,7 +3,7 @@ from django.db import models from django.forms import Media from django.urls import reverse -from django.utils.html import format_html_join +from django.utils.html import format_html, format_html_join class LinkFieldAdminMixin: From 2e315e4e6c1bd516b964eef1fefdf5a28c7c27ef Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 16:04:40 +0200 Subject: [PATCH 12/14] update doc --- README.md | 14 ++++++++++++++ django_adminlink/models.py | 0 docs/source/getting_started.rst | 14 ++++++++++++++ docs/source/installation.rst | 4 ++-- 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 django_adminlink/models.py diff --git a/README.md b/README.md index 5d3cc82..4965878 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,20 @@ You can install the package with: pip install django-adminlink ``` +You do *not* need to add `'django_adminlink'` to the `INSTALLED_APPS` settings *unless*, you use the `SingleItemActionMixin` or a derived product from it, since then +you need to make use of the `static/js/single_admin_action.js` file that ships with it. So then the `INSTALLED_APPS` looks like: + +```python3 +# settings.py + +# … + +INSTALLED_APPS = [ + # …, + 'django_adminlink' +] +``` + ## Usage Once the package is installed, we can work with the mixins provided by the package. diff --git a/django_adminlink/models.py b/django_adminlink/models.py new file mode 100644 index 0000000..e69de29 diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 8cded40..cf59537 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -14,3 +14,17 @@ Once the package is installed, you can use the `LinkFieldAdminMixin` mixin in th list_display = ['__str__', 'genre'] If `genre` is a `ForeignKey` to a `Genre` model for example, and `Genre` has its own `ModelAdmin`, it will automatically convert `genre` into a column that adds a link to the admin detail view of the corresponding genre. + + +Another option is to use with the `SingleItemActionMixin` to add a button per row to do (one or more) actions for that specific line with: + + ..code-block:: python3 + + from django.contrib import admin + from django_adminlink.admin import SingleItemActionMixin + + @admin.register(Movie) + class MovieAdmin(SingleItemActionMixin, admin.ModelAdmin): + action_buttons = {'delete': 'delete_selected'} + +here the `action_buttons` is a dictionary (or list) of labels that map to the admin actions. If the label is the same for each admin action, you can use a list, where you thus list the label and admin action only once. \ No newline at end of file diff --git a/docs/source/installation.rst b/docs/source/installation.rst index 4c2b42f..615647c 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -8,5 +8,5 @@ The package can be fetched as `django-adminlink`, so for example with `pip` with pip3 install django-adminlink -The item is not a Django app, so one should *not* to include it in the `INSTALLED_APPS`. It is only a module that -offers some functionality to use in Django applications. \ No newline at end of file +The item is a Django app, but you do not per se have to install it as such. If you don't make use of the `SingleItemActionMixin`, +you don't need to add `'django_adminlink'` to the `INSTALLED_APPS`, otherwise you need to do this to include the static file. \ No newline at end of file From f3afcf24b495fce9d64f4f396b64c25f77431e8c Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 16:19:09 +0200 Subject: [PATCH 13/14] grammar fix --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4965878..88cc127 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ You can install the package with: pip install django-adminlink ``` -You do *not* need to add `'django_adminlink'` to the `INSTALLED_APPS` settings *unless*, you use the `SingleItemActionMixin` or a derived product from it, since then -you need to make use of the `static/js/single_admin_action.js` file that ships with it. So then the `INSTALLED_APPS` looks like: +You do *not* need to add `'django_adminlink'` to the `INSTALLED_APPS` settings *unless* you use the `SingleItemActionMixin` or a derived product from it. In that case, +you need to make use of the `static/js/single_admin_action.js` file that ships with it. Then the `INSTALLED_APPS` looks like: + ```python3 # settings.py @@ -70,7 +71,7 @@ class MovieAdmin(SingleItemActionMixin, admin.ModelAdmin): One can work with a dictionary that has as key the "label" of the button, and as value the name (key) of the action to work with. This will add a button with the label "delete" as last column. When clicked, that row, and only that row is then removed. -The package does not perform the action itself: it works with a small amount of *JavaScript* that just disables all checkboxes, enables the one of the selected row, and finally submits the action form, and lets Django handle the logic further. +The package does not perform the action itself: it works with a small amount of *JavaScript* that just disables all checkboxes, enables only the checkbox of the selected row, and finally submits the action form, letting Django handle the rest of the logic. If the label(s) and action(s) are the same, one can also work with a list of the names of the actions, like: From 56f0a32c437543763ba579248f67a79af2ca5806 Mon Sep 17 00:00:00 2001 From: Willem Van Onsem Date: Sat, 26 Apr 2025 16:22:14 +0200 Subject: [PATCH 14/14] 0.1.0 -> 0.2.0 --- docs/source/conf.py | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c7958f7..0933763 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,8 +11,8 @@ copyright = "2025, Willem Van Onsem" author = "Willem Van Onsem" -release = "0.1.0" -version = "0.1.0" +release = "0.2.0" +version = "0.2.0" path.insert(0, dirname(dirname(dirname(__file__)))) diff --git a/pyproject.toml b/pyproject.toml index a185141..c9ca9c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "django-adminlink" -version = "0.1.0" +version = "0.2.0" authors = [{name = "Willem Van Onsem", email = "yourfriends@hapytex.eu"}] [build-system]