Admin Utilities
Note
This documentation page is aimed at developers who want to customize, change or extend the code of OpenWISP Utils in order to modify its behavior (e.g.: for personal or commercial purposes or to fix a bug, implement a new feature or contribute to the project in general).
If you aren't a developer and you are looking for information on how to use OpenWISP, please refer to:
openwisp_utils.admin.TimeReadonlyAdminMixin
Admin mixin which adds two read only fields created
and modified
.
This is an admin mixin for models inheriting TimeStampedEditableModel
which adds the fields created
and modified
to the database.
openwisp_utils.admin.ReadOnlyAdmin
A read-only ModelAdmin
base class.
Will include the id
field by default, which can be excluded by
supplying the exclude
attribute, e.g.:
from openwisp_utils.admin import ReadOnlyAdmin
class PostAuthReadOnlyAdmin(ReadOnlyAdmin):
exclude = ["id"]
openwisp_utils.admin.AlwaysHasChangedMixin
A mixin designed for inline items and model forms, ensures the item is created even if the default values are unchanged.
Without this, when creating new objects, inline items won't be saved unless users change the default values.
openwisp_utils.admin.CopyableFieldsAdmin
An admin class that allows to set admin fields to be read-only and makes it easy to copy the fields contents.
Useful for auto-generated fields such as UUIDs, secret keys, tokens, etc.
openwisp_utils.admin.UUIDAdmin
This class is a subclass of CopyableFieldsAdmin
which sets uuid
as
the only copyable field. This class is kept for backward compatibility and
convenience, since different models of various OpenWISP modules show
uuid
as the only copyable field.
openwisp_utils.admin.ReceiveUrlAdmin
An admin class that provides an URL as a read-only input field (to make it easy and quick to copy/paste).
openwisp_utils.admin.HelpTextStackedInline
A stacked inline admin class that displays a help text for entire inline object. Following is an example:
from openwisp_utils.admin import HelpTextStackedInline
class SubnetDivisionRuleInlineAdmin(
MultitenantAdminMixin, TimeReadonlyAdminMixin, HelpTextStackedInline
):
model = Model
# It is required to set "help_text" attribute
help_text = {
# (required) Help text to display
"text": _(
"Please keep in mind that once the subnet division rule is created "
'and used, changing "Size" and "Number of Subnets" and decreasing '
'"Number of IPs" will not be possible.'
),
# (optional) You can provide a link to documentation for user reference
"documentation_url": (
"https://github.com/openwisp/openwisp-utils"
),
# (optional) Icon to be shown along with help text. By default it uses
# "/static/admin/img/icon-alert.svg"
"image_url": "/static/admin/img/icon-alert.svg",
}
openwisp_utils.admin_theme.filters.InputFilter
The admin_theme
sub app of this package provides an input filter that
can be used in the changelist page to filter UUIDField
or
CharField
.
Code example:
from django.contrib import admin
from openwisp_utils.admin_theme.filters import InputFilter
from my_app.models import MyModel
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_filter = [
("my_field", InputFilter),
"other_field",
# ...
]
By default InputFilter
use exact lookup to filter items which matches
to the value being searched by the user. But this behavior can be changed
by modifying InputFilter
as following:
from django.contrib import admin
from openwisp_utils.admin_theme.filters import InputFilter
from my_app.models import MyModel
class MyInputFilter(InputFilter):
lookup = "icontains"
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_filter = [
("my_field", MyInputFilter),
"other_field",
# ...
]
To know about other lookups that can be used please check Django Lookup API Reference
openwisp_utils.admin_theme.filters.SimpleInputFilter
A stripped down version of
openwisp_utils.admin_theme.filters.InputFilter
that provides
flexibility to customize filtering. It can be used to filter objects using
indirectly related fields.
The derived filter class should define the queryset
method as shown in
following example:
from django.contrib import admin
from openwisp_utils.admin_theme.filters import SimpleInputFilter
from my_app.models import MyModel
class MyInputFilter(SimpleInputFilter):
parameter_name = "shelf"
title = _("Shelf")
def queryset(self, request, queryset):
if self.value() is not None:
return queryset.filter(name__icontains=self.value())
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_filter = [
MyInputFilter,
"other_field",
# ...
]
openwisp_utils.admin_theme.filters.AutocompleteFilter
The admin_theme
sub app of this package provides an auto complete
filter that uses the django-autocomplete widget to load filter data
asynchronously.
This filter can be helpful when the number of objects is too large to load all at once which may cause the slow loading of the page.
from django.contrib import admin
from openwisp_utils.admin_theme.filters import AutocompleteFilter
from my_app.models import MyModel, MyOtherModel
class MyAutoCompleteFilter(AutocompleteFilter):
field_name = "field"
parameter_name = "field_id"
title = _("My Field")
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_filter = [MyAutoCompleteFilter, ...]
@admin.register(MyOtherModel)
class MyOtherModelAdmin(admin.ModelAdmin):
search_fields = ["id"]
To customize or know more about it, please refer to the django-admin-autocomplete-filter documentation.
Customizing the Submit Row in OpenWISP Admin
In the OpenWISP admin interface, the submit_line.html
template
controls the rendering of action buttons in the model form's submit row.
OpenWISP Utils extends this template to allow the addition of custom
buttons.
To add custom buttons, you can use the additional_buttons
context
variable. This variable should be a list of dictionaries, each
representing a button with customizable properties such as type, class,
value, title, URL, or even raw HTML content.
Here's an example of adding a custom button with both standard properties
and raw HTML to the submit row in the change_view
method:
from django.contrib import admin
from django.utils.safestring import mark_safe
from .models import MyModel
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
def change_view(
self, request, object_id, form_url="", extra_context=None
):
extra_context = extra_context or {}
extra_context["additional_buttons"] = [
{
"type": "button",
"class": "btn btn-secondary",
"value": "Custom Action",
"title": "Perform a custom action",
"url": "https://example.com",
},
{
"raw_html": mark_safe(
'<button type="button" class="btn btn-warning" '
"onclick=\"alert('This is a raw HTML button!')\">"
"Raw HTML Button</button>"
)
},
]
return super().change_view(
request, object_id, form_url, extra_context
)
In this example, two buttons are added to the submit row:
A standard button labeled "Custom Action" with a link to https://example.com.
A button rendered using raw HTML that triggers an alert when clicked, labeled "Raw HTML Button." The raw HTML is wrapped in mark_safe to ensure it is rendered correctly.
The mark_safe function is necessary to ensure that the raw HTML is rendered as HTML and not escaped as plain text.