123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- ========================
- django-changelist-inline
- ========================
- Inline Changelists for Django
- Overview
- ========
- Django Admin comes with inlines_ which allows you to display forms to edit
- related objects from the parent object's change form. While it's technically
- possible to use this infrastructure to display list of related objects, it
- gets hacky pretty fast.
- Here's where *django-changelist-inline* comes into play. It allows you to embed
- the standard list of objects as an inline on the parent object's change form.
- Internally, it uses a subclass of ``ModelAdmin``, which means you can customize
- the list as you'd normally do. Additionally, you can display links below the
- list of objects.
- Usage Example
- =============
- Let's assume you have a Django project with two models - ``Thing`` and
- ``RelatedThing`` and that you want to display list of ``RelatedThing`` objects
- as an inline in ``Thing`` change form. The follwing snippet provides an example
- of how to implement that using *django-changelist-inline*:
- .. code-block:: python
- # -*- coding: utf-8 -*-
- from urllib.parse import urlencode
- from django.contrib import admin
- from django.urls import reverse
- from django.utils.safestring import mark_safe
- from django_changelist_inline import (
- ChangelistInline,
- ChangelistInlineAdmin,
- ChangelistInlineModelAdmin,
- )
- from testing.models import RelatedThing, Thing
- @admin.register(RelatedThing)
- class RelatedThingModelAdmin(admin.ModelAdmin):
- list_display = ('pk', 'name')
- class RelatedThingChangelistInline(ChangelistInline):
- model = RelatedThing
- class ChangelistModelAdmin(ChangelistInlineModelAdmin):
- list_display = ('name', 'format_actions')
- list_display_links = None
- list_per_page = 5
- def get_queryset(self, request):
- return RelatedThing.objects.filter(thing=self.parent_instance)
- @mark_safe
- def format_actions(self, obj=None):
- if obj is None:
- return self.empty_value_display
- change_link_url = reverse(
- 'admin:{app_label}_{model_name}_change'.format(
- app_label=RelatedThing._meta.app_label,
- model_name=RelatedThing._meta.model_name,
- ),
- args=[obj.pk],
- )
- return (
- f'<a class="button" href="{change_link_url}">'
- 'Edit'
- '</a>'
- )
- format_actions.short_description = 'Actions'
- @property
- def title(self):
- return 'Linked Related Things'
- @property
- def no_results_message(self):
- return 'No Related Things?'
- def get_add_url(self, request):
- result = super().get_add_url(request)
- if result is not None:
- return result + '?' + urlencode({
- 'thing': self.parent_instance.pk,
- })
- return result
- def get_show_all_url(self, request):
- result = super().get_show_all_url(request)
- if result is not None:
- return result + '?' + urlencode({
- 'thing': self.parent_instance.pk,
- })
- return result
- def get_toolbar_links(self, request):
- return (
- '<a href="https://www.bthlabs.pl/">'
- 'BTHLabs'
- '</a>'
- )
- @admin.register(Thing)
- class ThingModelAdmin(ChangelistInlineAdmin):
- inlines = (RelatedThingChangelistInline,)
- API
- ===
- ``ChangelistInline`` objects
- ----------------------------
- The ``ChangelistInline`` class is the center piece of the API. It's
- designed to be used in a ``ModelAdmin``'s ``inlines``.
- In order for it to work, you'll need to define the ``model`` property and
- embed ``ChangelistModelAdmin`` class, which should be a subclass of
- ``ChangelistInlineModelAdmin``.
- ``ChangelistInlineModelAdmin`` objects
- --------------------------------------
- The ``ChangelistInlineModelAdmin`` is a customized ``ModelAdmin`` subclass
- which provides sane defaults and additional functionality for inline
- changelists.
- **Changelist sanitization**
- This subclass overrides the following attributes and methods of ``ModelAdmin``
- to provide sane defaults:
- * ``list_editable`` - set to empty tuple to disable editing of the list,
- * ``list_filter`` - set to empty tuple to disable filtering of the list,
- * ``search_fields`` - set to empty tuple to disable searching,
- * ``date_hierarchy`` - set to ``None``,
- * ``sortable_by`` - set to empty tuple to disable sorting,
- * ``get_actions()`` - returns empty list to disable actions.
- **Additional functionality**
- To allow customization and to expose additional functionality,
- ``ChangelistInlineModelAdmin`` provides the following additional methods:
- * ``title`` property - returns the model's *verbose name* by default.
- * ``no_results_message`` property - returns text to display in place of the
- table if no objects are fetched from the DB.
- * ``get_add_url(request)`` - returns URL for the model's add form, if the
- user has the add permission. Return ``None`` to hide the add link.
- * ``get_show_all_url(request)`` - returns URL for the model's changelist, if
- the user has the view permission. Return ``None`` to hide the show all link.
- * ``get_toolbar_links(request)`` - returns ``None`` by default. Override this
- to return string with additional ``<a/>`` elements to render in the toolbar.
- The return value is marked safe in the template.
- ``ChangelistInlineAdmin`` objects
- ---------------------------------
- The ``ChangelistInlineAdmin`` class is a base class for ``ModelAdmin``
- subclasses that use inline changelists.
- ``ChangelistInlineAdminMixin``
- ------------------------------
- A mixin class that is used to properly configure changelist inlines in the
- parent ``ModelAdmin``. Overrides ``get_inlines(request, obj=None)`` and
- ``get_inline_instances(request, obj=None)`` methods.
- If you can't use ``ChangelistInlineAdmin`` as you base class, you can use this
- mixin to enable inline changelists:
- .. code-block:: python
- @admin.register(Thing)
- class ThingModelAdmin(ChangelistInlineAdminMixin, MyBaseModelAdmin):
- ...
- Author
- ------
- *django-changelist-inline* is developed by `Tomek Wójcik`_.
- License
- -------
- *django-changelist-inline* is licensed under the MIT License.
- .. _inlines: https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#inlinemodeladmin-objects
- .. _Tomek Wójcik: https://www.bthlabs.pl/
|