mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #19425 - Added InlineModelAdmin.get_extra hook.
Thanks dave@ for the suggestion and Rohan Jain for the patch.
This commit is contained in:
		| @@ -1512,6 +1512,10 @@ class InlineModelAdmin(BaseModelAdmin): | ||||
|             js.extend(['SelectBox.js', 'SelectFilter2.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): | ||||
|         """Returns a BaseInlineFormSet class for use in admin add/change views.""" | ||||
|         if self.declared_fieldsets: | ||||
| @@ -1538,7 +1542,7 @@ class InlineModelAdmin(BaseModelAdmin): | ||||
|             "fields": fields, | ||||
|             "exclude": exclude, | ||||
|             "formfield_callback": partial(self.formfield_for_dbfield, request=request), | ||||
|             "extra": self.extra, | ||||
|             "extra": self.get_extra(request, obj, **kwargs), | ||||
|             "max_num": self.max_num, | ||||
|             "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 | ||||
|     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: | ||||
|  | ||||
| .. attribute:: InlineModelAdmin.max_num | ||||
| @@ -1762,6 +1767,26 @@ The ``InlineModelAdmin`` class adds: | ||||
|     Returns a ``BaseInlineFormSet`` class for use in admin add/change views. | ||||
|     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 | ||||
| --------------------------------------------------------------------------- | ||||
|  | ||||
|   | ||||
| @@ -292,6 +292,10 @@ Minor features | ||||
|   :meth:`~django.db.models.query.QuerySet.select_related` can be cleared using | ||||
|   ``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 | ||||
| ===================================== | ||||
|  | ||||
|   | ||||
| @@ -129,6 +129,17 @@ class ChildModel1Inline(admin.TabularInline): | ||||
| class ChildModel2Inline(admin.StackedInline): | ||||
|     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 | ||||
| class SightingInline(admin.TabularInline): | ||||
|     model = Sighting | ||||
| @@ -150,4 +161,5 @@ site.register(Author, AuthorAdmin) | ||||
| site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline, ReadOnlyInlineInline]) | ||||
| site.register(ProfileCollection, inlines=[ProfileInline]) | ||||
| site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2Inline]) | ||||
| site.register(BinaryTree, inlines=[BinaryTreeAdmin]) | ||||
| site.register(ExtraTerrestrial, inlines=[SightingInline]) | ||||
|   | ||||
| @@ -183,6 +183,12 @@ class ChildModel2(models.Model): | ||||
|     def get_absolute_url(self): | ||||
|         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 | ||||
|  | ||||
| class LifeForm(models.Model): | ||||
|   | ||||
| @@ -12,7 +12,7 @@ from .admin import InnerInline, TitleInline, site | ||||
| from .models import (Holder, Inner, Holder2, Inner2, Holder3, Inner3, Person, | ||||
|     OutfitItem, Fashionista, Teacher, Parent, Child, Author, Book, Profile, | ||||
|     ProfileCollection, ParentModelWithCustomPk, ChildModel1, ChildModel2, | ||||
|     Sighting, Title, Novel, Chapter, FootNote) | ||||
|     Sighting, Title, Novel, Chapter, FootNote, BinaryTree) | ||||
|  | ||||
|  | ||||
| @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) | ||||
| @@ -193,6 +193,18 @@ class TestInline(TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         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',)) | ||||
| class TestInlineMedia(TestCase): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user