Fixed #19425 - Added InlineModelAdmin.get_extra hook.
Thanks dave@ for the suggestion and Rohan Jain for the patch.
This commit is contained in:
parent
7902fd74f1
commit
36aecb12b8
|
@ -1512,6 +1512,10 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
js.extend(['SelectBox.js', 'SelectFilter2.js'])
|
js.extend(['SelectBox.js', 'SelectFilter2.js'])
|
||||||
return forms.Media(js=[static('admin/js/%s' % url) for url in js])
|
return forms.Media(js=[static('admin/js/%s' % url) for url in js])
|
||||||
|
|
||||||
|
def get_extra(self, request, obj=None, **kwargs):
|
||||||
|
"""Hook for customizing the number of extra inline forms."""
|
||||||
|
return self.extra
|
||||||
|
|
||||||
def get_formset(self, request, obj=None, **kwargs):
|
def get_formset(self, request, obj=None, **kwargs):
|
||||||
"""Returns a BaseInlineFormSet class for use in admin add/change views."""
|
"""Returns a BaseInlineFormSet class for use in admin add/change views."""
|
||||||
if self.declared_fieldsets:
|
if self.declared_fieldsets:
|
||||||
|
@ -1538,7 +1542,7 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
"fields": fields,
|
"fields": fields,
|
||||||
"exclude": exclude,
|
"exclude": exclude,
|
||||||
"formfield_callback": partial(self.formfield_for_dbfield, request=request),
|
"formfield_callback": partial(self.formfield_for_dbfield, request=request),
|
||||||
"extra": self.extra,
|
"extra": self.get_extra(request, obj, **kwargs),
|
||||||
"max_num": self.max_num,
|
"max_num": self.max_num,
|
||||||
"can_delete": can_delete,
|
"can_delete": can_delete,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1715,6 +1715,11 @@ The ``InlineModelAdmin`` class adds:
|
||||||
The dynamic link will not appear if the number of currently displayed forms
|
The dynamic link will not appear if the number of currently displayed forms
|
||||||
exceeds ``max_num``, or if the user does not have JavaScript enabled.
|
exceeds ``max_num``, or if the user does not have JavaScript enabled.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
|
||||||
|
:meth:`InlineModelAdmin.get_extra` also allows you to customize the number
|
||||||
|
of extra forms.
|
||||||
|
|
||||||
.. _ref-contrib-admin-inline-max-num:
|
.. _ref-contrib-admin-inline-max-num:
|
||||||
|
|
||||||
.. attribute:: InlineModelAdmin.max_num
|
.. attribute:: InlineModelAdmin.max_num
|
||||||
|
@ -1762,6 +1767,26 @@ The ``InlineModelAdmin`` class adds:
|
||||||
Returns a ``BaseInlineFormSet`` class for use in admin add/change views.
|
Returns a ``BaseInlineFormSet`` class for use in admin add/change views.
|
||||||
See the example for :class:`ModelAdmin.get_formsets`.
|
See the example for :class:`ModelAdmin.get_formsets`.
|
||||||
|
|
||||||
|
.. method:: InlineModelAdmin.get_extra(self, request, obj=None, **kwargs)
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
|
||||||
|
Returns the number of extra inline forms to use. By default, returns the
|
||||||
|
:attr:`InlineModelAdmin.extra` attribute.
|
||||||
|
|
||||||
|
Override this method to programmatically determine the number of extra
|
||||||
|
inline forms. For example, this may be based on the model instance
|
||||||
|
(passed as the keyword argument ``obj``)::
|
||||||
|
|
||||||
|
class BinaryTreeAdmin(admin.TabularInline):
|
||||||
|
model = BinaryTree
|
||||||
|
|
||||||
|
def get_extra(self, request, obj=None, **kwargs):
|
||||||
|
extra = 2
|
||||||
|
if obj:
|
||||||
|
return extra - obj.binarytree_set.count()
|
||||||
|
return extra
|
||||||
|
|
||||||
Working with a model with two or more foreign keys to the same parent model
|
Working with a model with two or more foreign keys to the same parent model
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,10 @@ Minor features
|
||||||
:meth:`~django.db.models.query.QuerySet.select_related` can be cleared using
|
:meth:`~django.db.models.query.QuerySet.select_related` can be cleared using
|
||||||
``select_related(None)``.
|
``select_related(None)``.
|
||||||
|
|
||||||
|
* The :meth:`~django.contrib.admin.InlineModelAdmin.get_extra` method on
|
||||||
|
:class:`~django.contrib.admin.InlineModelAdmin` may be overridden to
|
||||||
|
customize the number of extra inline forms.
|
||||||
|
|
||||||
Backwards incompatible changes in 1.6
|
Backwards incompatible changes in 1.6
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,17 @@ class ChildModel1Inline(admin.TabularInline):
|
||||||
class ChildModel2Inline(admin.StackedInline):
|
class ChildModel2Inline(admin.StackedInline):
|
||||||
model = ChildModel2
|
model = ChildModel2
|
||||||
|
|
||||||
|
# admin for #19425
|
||||||
|
class BinaryTreeAdmin(admin.TabularInline):
|
||||||
|
model = BinaryTree
|
||||||
|
|
||||||
|
def get_extra(self, request, obj=None, **kwargs):
|
||||||
|
extra = 2
|
||||||
|
if obj:
|
||||||
|
return extra - obj.binarytree_set.count()
|
||||||
|
|
||||||
|
return extra
|
||||||
|
|
||||||
# admin for #19524
|
# admin for #19524
|
||||||
class SightingInline(admin.TabularInline):
|
class SightingInline(admin.TabularInline):
|
||||||
model = Sighting
|
model = Sighting
|
||||||
|
@ -150,4 +161,5 @@ site.register(Author, AuthorAdmin)
|
||||||
site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline, ReadOnlyInlineInline])
|
site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline, ReadOnlyInlineInline])
|
||||||
site.register(ProfileCollection, inlines=[ProfileInline])
|
site.register(ProfileCollection, inlines=[ProfileInline])
|
||||||
site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2Inline])
|
site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2Inline])
|
||||||
|
site.register(BinaryTree, inlines=[BinaryTreeAdmin])
|
||||||
site.register(ExtraTerrestrial, inlines=[SightingInline])
|
site.register(ExtraTerrestrial, inlines=[SightingInline])
|
||||||
|
|
|
@ -183,6 +183,12 @@ class ChildModel2(models.Model):
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return '/child_model2/'
|
return '/child_model2/'
|
||||||
|
|
||||||
|
|
||||||
|
# Models for #19425
|
||||||
|
class BinaryTree(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
parent = models.ForeignKey('self', null=True, blank=True)
|
||||||
|
|
||||||
# Models for #19524
|
# Models for #19524
|
||||||
|
|
||||||
class LifeForm(models.Model):
|
class LifeForm(models.Model):
|
||||||
|
|
|
@ -12,7 +12,7 @@ from .admin import InnerInline, TitleInline, site
|
||||||
from .models import (Holder, Inner, Holder2, Inner2, Holder3, Inner3, Person,
|
from .models import (Holder, Inner, Holder2, Inner2, Holder3, Inner3, Person,
|
||||||
OutfitItem, Fashionista, Teacher, Parent, Child, Author, Book, Profile,
|
OutfitItem, Fashionista, Teacher, Parent, Child, Author, Book, Profile,
|
||||||
ProfileCollection, ParentModelWithCustomPk, ChildModel1, ChildModel2,
|
ProfileCollection, ParentModelWithCustomPk, ChildModel1, ChildModel2,
|
||||||
Sighting, Title, Novel, Chapter, FootNote)
|
Sighting, Title, Novel, Chapter, FootNote, BinaryTree)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||||
|
@ -193,6 +193,18 @@ class TestInline(TestCase):
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(Sighting.objects.filter(et__name='Martian').count(), 1)
|
self.assertEqual(Sighting.objects.filter(et__name='Martian').count(), 1)
|
||||||
|
|
||||||
|
def test_custom_get_extra_form(self):
|
||||||
|
bt_head = BinaryTree.objects.create(name="Tree Head")
|
||||||
|
bt_child = BinaryTree.objects.create(name="First Child", parent=bt_head)
|
||||||
|
|
||||||
|
# The total number of forms will remain the same in either case
|
||||||
|
total_forms_hidden = '<input id="id_binarytree_set-TOTAL_FORMS" name="binarytree_set-TOTAL_FORMS" type="hidden" value="2" />'
|
||||||
|
response = self.client.get('/admin/admin_inlines/binarytree/add/')
|
||||||
|
self.assertContains(response, total_forms_hidden)
|
||||||
|
|
||||||
|
response = self.client.get("/admin/admin_inlines/binarytree/%d/" % bt_head.id)
|
||||||
|
self.assertContains(response, total_forms_hidden)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||||
class TestInlineMedia(TestCase):
|
class TestInlineMedia(TestCase):
|
||||||
|
|
Loading…
Reference in New Issue