Documentation¶
django-nested-admin is a project that makes it possible to nest admin inlines (that is, to define inlines on InlineModelAdmin classes). It also allows these inlines to be sorted by drag-and-drop, and has optional Grappelli support.
Compatibility¶
django-nested-admin is compatible with Django 1.8+ and Python versions 2.7 and 3.4+. It is also compatible with Grappelli and Django Suit. It does not require Grappelli or Django Suit for the drag-and-drop sorting features.
Contents¶
Quick start guide¶
Django (version 1.8+) needs to be installed to use django-nested-admin.
Installation¶
pip install django-nested-admin
Go to GitHub if you need to download or install from source.
Setup¶
Open settings.py
and add nested_admin
to your INSTALLED_APPS
INSTALLED_APPS = (
# ...
'nested_admin',
)
Add URL-patterns:
urlpatterns = patterns('',
# ...
url(r'^_nested_admin/', include('nested_admin.urls')),
)
Collect the static files:
$ python manage.py collectstatic
Example Usage¶
In order to use django-nested-admin
, use the following classes in
place of their django admin equivalents:
django.contrib.admin | nested_admin |
ModelAdmin | NestedModelAdmin |
InlineModelAdmin | NestedInlineModelAdmin |
StackedInline | NestedStackedInline |
TabularInline | NestedTabularInline |
There is also nested_admin.NestedGenericStackedInline
and
nested_admin.NestedGenericTabularInline
which are the nesting-capable
versions of GenericStackedInline
and GenericTabularInline
in
django.contrib.contenttypes.admin
.
# An example admin.py for a Table of Contents app
from django.contrib import admin
import nested_admin
from .models import TableOfContents, TocArticle, TocSection
class TocArticleInline(nested_admin.NestedStackedInline):
model = TocArticle
sortable_field_name = "position"
class TocSectionInline(nested_admin.NestedStackedInline):
model = TocSection
sortable_field_name = "position"
inlines = [TocArticleInline]
class TableOfContentsAdmin(nested_admin.NestedModelAdmin):
inlines = [TocSectionInline]
admin.site.register(TableOfContents, TableOfContentsAdmin)
Why use django-nested-admin?¶
django-nested-admin | django-super-inlines | django-nested-inlines | dj-nested-inlines | django-nested-inline | |
---|---|---|---|---|---|
Nested inlines | ✓ | ✓ | ✓ | ✓ | ✓ |
Grappelli support | ✓ | ✓ | |||
Generic inlines support | ✓ | ✓ | |||
Drag-and-drop sorting | ✓ | ||||
Selenium Tests | ✓ | ||||
Django Suit support | ✓ |
Above, you will find a feature comparison of all other implementations of nested inlines in the django admin of which I am aware. django-nested-inline, django-nested-inlines, and dj-nested-inlines are all variations upon a patch posted to Django ticket #9025. django-nested-inlines has had no commits since 2013 and appears to be abandoned, with dj-nested-inlines being a better maintained fork. It, along with django-nested-inline, are maintained insofar as the maintainers merge in pull requests and update PyPI, but they do not appear to be working on improving these implementations themselves. django-super-inlines is a fresher take on the problem, and looks to be more promising.
The largest functional difference between django-nested-admin and these other projects is its support for drag-and-drop sorting functionality within and between inlines, similar to Grappelli’s sortable inline feature (though it does not require Grappelli). It also has fairly extensive test coverage. And lastly django-nested-admin is and will remain an integral part of the CMS that powers TheAtlantic.com (and CityLab.com) where it is used by editors to curate the homepages, email newsletters, and landing pages for special projects and site sections (the way we used django-nested-admin to power the curation of TheAtlantic.com’s homepage was the subject of a talk we gave at the 2015 Djangocon).
Customization¶
Sortables¶
The steps for enabling drag-and-drop sorting functionality is identical to Grappelli’s (even with the vanilla Django admin), so the Grappelli documentation for this feature is the best reference. This is equally true of sortables in Django Suit—do not follow Django Suit’s instructions for sortables, as they will not work. The other features of Grappelli have not been ported to work with vanilla Django, but in principle they should all still work with nested inlines using django-nested-admin if Grappelli is installed. If you run into any difficulty with this, please create an issue on this project’s Github.
If you want to have a sortable inline and also want to hide the field you’re sorting, you can use SortableHiddenMixin
. Note that this mixin sets sortable_field_name
to position
by default (though this can be overridden by setting sortable_field_name
on your inline class) and must be inherited prior to NestedStackedInline
or NestedTabularInline
.
import nested_admin
from django.contrib import admin
from .models import TableOfContents, TocArticle, TocSection
class TocArticleInline(nested_admin.SortableHiddenMixin,
nested_admin.NestedStackedInline):
model = TocArticle
class TocSectionInline(nested_admin.SortableHiddenMixin,
nested_admin.NestedStackedInline):
model = TocSection
inlines = [TocArticleInline]
@admin.register(TableOfContents)
class TableOfContentsAdmin(nested_admin.NestedModelAdmin):
inlines = [TocSectionInline]
Events¶
Adding or removing an inline fires the formset:added
and formset:removed
events, respectively, that were added to Django in 1.9 (#15760). This is particularly useful for when you need to execute javascript upon an inline being added (for instance, to initialize a custom widget). The API is the same as Django 1.9, so reference the official Django docs for information about how to use these events. In addition, django-nested-admin also emits events for when the delete checkbox (or button, in Grappelli) is toggled with the formset:deleted
and formset:undeleted
events. Less likely to be used, but still available, are the following events:
djnesting:mutate
- Fired whenever the state of a formset changes
djnesting:initialized
- Fired after an inline has been initialized, either on load or after being added
djnesting::attrchanged
- Fired whenever a drag-and-drop operation or removal necessitates changing the
name
,id
, andfor
attributes of the elements within a form or formset. Ideally custom Django widgets with javascript hooks should be written so that they do not need to be reinitialized if a form field’sid
orname
changes, but in cases where they do, use this event to refresh or reinitialize the bindings.
Integrations¶
django-polymorphic¶
Quickstart¶
Support for django-polymorphic is currently in beta. To use polymorphic
inlines with django-nested-admin follow the steps for
setting up django-polymorphic admin inline integration. The instructions
are identical with django-nested-admin, except that the classes you would
normally import from polymorphic.admin
should instead be imported from
nested_admin
and the classes themselves should be prefixed with
Nested
For example:
# Instead of these imports
from django.contrib.admin import ModelAdmin
from polymorphic.admin import (
PolymorphicInlineSupportMixin, StackedPolymorphicInline)
# One should import:
from nested_admin import (
NestedModelAdmin,
NestedPolymorphicInlineSupportMixin, NestedStackedPolymorphicInline)
The polymorphic inlines used with django-nested-admin can have other inlines nested inside them, or even other polymorphic inlines. The only requirement is that all ModelAdmin and InlineAdmin classes inherit from the appropriate nested version.
Example¶
from django.contrib import admin
import nested_admin
from .models import (
Store, Customer, GuestCustomer, LoggedInCustomer, OrderItem, Product, WishListItem,
Order, WishList, Payment, CreditCardPayment, BankPayment)
class PaymentInline(nested_admin.NestedStackedPolymorphicInline):
model = Payment
class CreditCardPaymentInline(nested_admin.NestedStackedPolymorphicInline.Child):
model = CreditCardPayment
class BankPayment(nested_admin.NestedStackedPolymorphicInline.Child):
model = BankPayment
child_inlines = (CreditCardPaymentInline, BankPayment)
class ProductInline(nested_admin.NestedStackedInline):
model = Product
class WishListItemInline(nested_admin.NestedStackedInline):
model = WishListItem
sortable_field_name = 'position'
class WishListInline(nested_admin.NestedStackedInline):
model = WishList
inlines = [WishListItemInline]
class OrderItemInline(nested_admin.NestedStackedInline):
model = OrderItem
class OrderInline(nested_admin.NestedTabularInline):
model = Order
inlines = [OrderItemInline, PaymentInline]
class CustomerInline(nested_admin.NestedStackedPolymorphicInline):
model = Customer
inlines = [OrderInline]
class GuestCustomerInline(nested_admin.NestedStackedPolymorphicInline.Child):
model = GuestCustomer
class LoggedInCustomerInline(nested_admin.NestedStackedPolymorphicInline.Child):
model = LoggedInCustomer
inlines = [WishListInline]
child_inlines = (GuestCustomerInline, LoggedInCustomerInline)
@admin.register(Store)
class StoreAdmin(nested_admin.NestedPolymorphicModelAdmin):
inlines = [CustomerInline]
Contributing¶
Editing javascript and css¶
This project uses webpack for building its
javascript and css. To install the dependencies for the build process, run
npm install
from the root of the repository. You can then run
npm run build
to rebuild the static files.
Running tests¶
django-nested-admin has fairly extensive test coverage.
The best way to run the tests is with tox,
which runs the tests against all supported Django installs. To run the tests
within a virtualenv run python runtests.py
from the repository directory.
The tests require a selenium webdriver to be installed. By default the tests
run with phantomjs, but it is also possible to run the tests with the chrome
webdriver by passing --selenium=chrome
to runtests.py or, if running with tox,
running tox -- --selenium=chrome
. See runtests.py --help
for a complete
list of the options available.
Pull requests are automatically run through Travis CI upon submission to verify that the changes do not introduce regressions.
Writing tests¶
The tests for this project are patterned off of the system that the Django project itself uses for tests (including the changes that are being made in 1.10), so Django’s guide on writing unit tests is a good place to start.
Selenium tests are difficult to write, particularly for complicated user
interactions such as drag-and-drop. To assist in writing tests for the
functionality of nested inlines, a base TestCase with methods for
executing the possible user interactions with inlines (e.g.
adding inlines, removing inlines, setting field values, drag-and-drop re-ordering)
is provided with base.BaseNestedAdminTestCase
.
Depending on what you are trying to test, it might make sense to add the test to one of the existing “test apps” in django-nested-admin. These include:
admin_widgets
- Integration tests for built-in Django widgets that use javascript, e.g.
prepopulated_fields
or ManyToManyFields withfilter_horizontal
. gfk
- Tests for
nested_admin.NestedGenericStackedInline
andnested_admin.NestedGenericTabularInline
one_deep
- Tests that compare screenshots of standard, non-nested inlines using the standard inline classes and their nested equivalents (but without any actual nesting), to ensure that the custom templates, css, and javascript used by django-nested-admin looks the same as their non-nested Django or Grappelli equivalents.
two_deep
- Tests for
nested_admin.NestedStackedInline
andnested_admin.NestedTabularInline
where there is only one “nested” inline (using two levels of inlines, hence “two deep”). three_deep
- Tests the same things as
two_deep
, except with inlines nested “three deep.”
If your test requires the creation of new test models, then it may make sense
to write a new test app. Create a new subdirectory under nested_admin/tests
with an __init__.py
, admin.py
, models.py
, and tests.py
. The
test runner will automatically add this to the list of INSTALLED_APPS
and execute the tests defined in tests.py
. The tests in two_deep
are the most complete, and can serve as a reference for how to use the
helper methods for simulating user interactions.
Changelog¶
3.2.4 (Aug 27, 2019)
- Fixed: Django 2.x
autocomplete_fields
deeply-nested initialization (#151) - Fixed: Bug that prevented a user from saving edits to nested inlines if they did not have add permissions to parent inlines. (#144)
- Fixed: Removed runtime dependency on setuptools (#150). Thanks @tari!
3.2.3 (Apr 28, 2019)
- Fixed: visual inconsistencies in grappelli tabular inline styles (#136)
- Fixed: numerous issues with django-polymorphic integration (#138)
- Feature: Added
SortableHiddenMixin
akin to grappelli’s GrappelliSortableHiddenMixin (#123). Thanks @brandenhall!
3.2.2 (Apr 9, 2019)
- Fixed: Django 2.x
autocomplete_fields
support (#118) - Fixed: (grappelli) proper initialization of admin widgets in deeply nested inlines (#122)
- Fixed: (grappelli) generic
related_lookup
andautocomplete_lookup_fields
(#114) - Fixed: (grappelli) Collapsible tabular inlines with
NestedTabularInline.classes
now work. (#90) - Fixed: Suppress validation errors of inlines nested beneath deleted inlines (#101)
3.2.0 (Apr 3, 2019)
- Feature: Added beta support for django-polymorphic admin (#86)
- Feature: Made compatible with Django 2.2 and 3.0. Django 3.0 is still in alpha, so the django-nested-admin compatibility is likewise not yet stable
- Fixed: django-nested-admin now respects permissions for inline model admins in Django 2.1+, including the new ‘view’ permission.
- Fixed: (grappelli) Collapsing inline groups now works for stacked inlines (thanks @maldn) (#121)
- Fixed: FileFields in deeply nested inlines now work in Django 2.1+ (thanks @btknu) (#111, #127)
- Fixed: Use correct translation for ‘Delete?’ text in templates (thanks @kigawas) (#116)
3.1.3 (Dec 15, 2018)
- Fixed: Use
jQuery.fn.length
, not.size
, for compatibility with jQuery 3, the version bundled with Django 2.1+ (#109)
3.1.2 (Sep 6, 2018)
- Fixed: Bug with grappelli that prevented deeply nested datepicker and timepicker widgets from working.
3.1.0 (Aug 13, 2018)
- Fixed: NestedTabularInline support in Django 2.0 (#97)
- Fixed: Ensure correct relative order of js media. (#71)
- Switch js build process to use webpack, without gulp
- Add test coverage reporting for both python and js code
3.0.21 (Nov 1, 2017)
- Fixed: Bug when saving child models that use django-polymorphic
- Feature: Made compatible with django-autocomplete-light (#84)
3.0.20 (Aug 2, 2017)
- Fixed: Correctly show inline label number in django admin 1.9+ (#79)
3.0.16 (Mar 10, 2017)
- Support Django 2.0
3.0.15 (Feb 27, 2017)
- Fixed: bug caused when
TEMPLATE['OPTIONS']['string_if_invalid']
is set (#70)
3.0.13 (Feb 13, 2017)
- Fixed: grappelli autocomplete widget support (#57)
- Improvement: enforce admin
min_num
setting in javascript
3.0.11 (Oct 18, 2016)
- Fixed: bug when multiple inlines share the same prefix (#60)
3.0.10 (Sep 13, 2016)
- Fixed: bug if
django.contrib.admin
precedesnested_admin
inINSTALLED_APPS
(#56) - Fixed: don’t show add inline link when
max_num = 0
(#54) - Improvement: Added
'djnesting:beforeadded
javascript event to ease integration with third-party admin widgets. (#47) - Feature: support Django 1.10 inline classes (for collapsing) (#32, #52)
3.0.8 (Jun 13, 2016)
- Fixed:
max_num
off-by-one error (#44) - Fixed: saving with a blank intermediate inline now works (#46)
3.0.5 (Jun 7, 2016)
- Fixed: ForeignKey widget on added inline (#45)
3.0.4 (June 3, 2016)
- Fixed: Support
prepopulated_fields
in grappelli (#43)
3.0.3 (May 26, 2016)
- Fixed: Bug with grappelli ForeignKey related lookup widget (thanks @sbussetti)
3.0.2 (April 17, 2016)
- Feature: django-suit support
- Fixed: javascript syntax error
- Fixed: bug where tabular inlines without sortables could not be updated
3.0.0 (April 13, 2016)
- Added documentation
- Fixed visual discrepancies between the appearance of nested and their usual appearance in Django and Grappelli. Added screenshot comparison tests to prevent future regressions.
- Support nesting of generic inlines (fixes #30)
- Support for
show_change_link
(fixes #22) - Support for Django 1.10dev
- Dropped support for version of Django prior to 1.8, which greatly simplified the Python code.
- Use gulp for building static assets, rewritten with scss and ES6
API reference¶
nested_admin
Package¶
nested_admin.tests
Module
License¶
The django code is licensed under the Simplified BSD
License. View the
LICENSE
file under the root directory for complete license and
copyright information.