diff --git a/CHANGELOG.txt b/CHANGELOG.txt index b9e05cce34..623403dca0 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -13,6 +13,7 @@ Changelog * `PageChooserBlock` can now accept a list/tuple of page models as `target_model` (Mikalai Radchuk) * Styling tweaks for the ModelAdmin's `IndexView` to be more inline with the Wagtail styleguide (Andy Babic) * Added `.nvmrc` to the project root for Node versioning support (Janneke Janssen) + * Added `form_fields_exclude` property to ModelAdmin views (Matheus Bratfisch) * Fix: Marked 'Date from' / 'Date to' strings in wagtailforms for translation (Vorlif) * Fix: Unreliable preview is now reliable by always opening in a new window (Kjartan Sverrisson) * Fix: Fixed placement of `{{ block.super }}` in `snippets/type_index.html` (LB (Ben Johnston)) diff --git a/docs/reference/contrib/modeladmin/create_edit_delete_views.rst b/docs/reference/contrib/modeladmin/create_edit_delete_views.rst index ad6c5c819e..e7fc133af1 100644 --- a/docs/reference/contrib/modeladmin/create_edit_delete_views.rst +++ b/docs/reference/contrib/modeladmin/create_edit_delete_views.rst @@ -150,3 +150,17 @@ See the following part of the docs to find out more: See the following part of the docs to find out more: :ref:`modeladmin_overriding_views` + +.. _modeladmin_form_fields_exclude: + +----------------------------------- +``ModelAdmin.form_fields_exclude`` +----------------------------------- + +**Expected value**: A list or tuple of fields names + +When using CreateView or EditView to create or update model instances, this +value will be passed to the edit form, so that any named fields will be +excluded from the form. This is particularly useful when registering ModelAdmin +classes for models from third-party apps, where defining panel configurations +on the Model itself is more complicated. diff --git a/docs/releases/1.10.rst b/docs/releases/1.10.rst index d8ee93470e..c760e561f2 100644 --- a/docs/releases/1.10.rst +++ b/docs/releases/1.10.rst @@ -23,6 +23,7 @@ Other features * ``PageChooserBlock`` can now accept a list/tuple of page models as ``target_model`` (Mikalai Radchuk) * Styling tweaks for the ModelAdmin's ``IndexView`` to be more inline with the Wagtail styleguide (Andy Babic) * Added `.nvmrc` to the project root for Node versioning support (Janneke Janssen) + * Added `form_fields_exclude` property to ModelAdmin views (Matheus Bratfisch) Bug fixes diff --git a/wagtail/contrib/modeladmin/options.py b/wagtail/contrib/modeladmin/options.py index 0dab6ae82a..66392277d1 100644 --- a/wagtail/contrib/modeladmin/options.py +++ b/wagtail/contrib/modeladmin/options.py @@ -142,6 +142,7 @@ class ModelAdmin(WagtailRegisterable): inspect_view_extra_js = [] form_view_extra_css = [] form_view_extra_js = [] + form_fields_exclude = [] def __init__(self, parent=None): """ @@ -158,7 +159,6 @@ class ModelAdmin(WagtailRegisterable): self.model, self.inspect_view_enabled) self.url_helper = self.get_url_helper_class()(self.model) - def get_permission_helper_class(self): """ Returns a permission_helper class to help with permission-based logic @@ -299,6 +299,12 @@ class ModelAdmin(WagtailRegisterable): """ return {} + def get_form_fields_exclude(self, request): + """ + Returns a list or tuple of fields names to be excluded from Create/Edit pages. + """ + return self.form_fields_exclude + def get_index_view_extra_css(self): css = ['wagtailmodeladmin/css/index.css'] css.extend(self.index_view_extra_css) diff --git a/wagtail/contrib/modeladmin/tests/test_simple_modeladmin.py b/wagtail/contrib/modeladmin/tests/test_simple_modeladmin.py index 0e75ca0236..8ef5ec5968 100644 --- a/wagtail/contrib/modeladmin/tests/test_simple_modeladmin.py +++ b/wagtail/contrib/modeladmin/tests/test_simple_modeladmin.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals +import mock from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from django.test import TestCase @@ -181,6 +182,16 @@ class TestCreateView(TestCase, WagtailTestUtils): # Check that a form error was raised self.assertFormError(response, 'form', 'title', "This field is required.") + def test_exclude_passed_to_extract_panel_definitions(self): + path_to_form_fields_exclude_property = 'wagtail.contrib.modeladmin.options.ModelAdmin.form_fields_exclude' + with mock.patch('wagtail.contrib.modeladmin.views.extract_panel_definitions_from_model_class') as m: + with mock.patch(path_to_form_fields_exclude_property, new_callable=mock.PropertyMock) as mock_form_fields_exclude: + mock_form_fields_exclude.return_value = ['123'] + + self.get() + mock_form_fields_exclude.assert_called() + m.assert_called_with(Book, exclude=mock_form_fields_exclude.return_value) + class TestInspectView(TestCase, WagtailTestUtils): fixtures = ['modeladmintest_test.json'] @@ -297,6 +308,16 @@ class TestEditView(TestCase, WagtailTestUtils): # Check that a form error was raised self.assertFormError(response, 'form', 'title', "This field is required.") + def test_exclude_passed_to_extract_panel_definitions(self): + path_to_form_fields_exclude_property = 'wagtail.contrib.modeladmin.options.ModelAdmin.form_fields_exclude' + with mock.patch('wagtail.contrib.modeladmin.views.extract_panel_definitions_from_model_class') as m: + with mock.patch(path_to_form_fields_exclude_property, new_callable=mock.PropertyMock) as mock_form_fields_exclude: + mock_form_fields_exclude.return_value = ['123'] + + self.get(1) + mock_form_fields_exclude.assert_called() + m.assert_called_with(Book, exclude=mock_form_fields_exclude.return_value) + class TestPageSpecificViews(TestCase, WagtailTestUtils): fixtures = ['modeladmintest_test.json'] diff --git a/wagtail/contrib/modeladmin/views.py b/wagtail/contrib/modeladmin/views.py index b78849cdae..203a76453a 100644 --- a/wagtail/contrib/modeladmin/views.py +++ b/wagtail/contrib/modeladmin/views.py @@ -115,7 +115,8 @@ class ModelFormView(WMABaseView, FormView): if hasattr(self.model, 'edit_handler'): edit_handler = self.model.edit_handler else: - panels = extract_panel_definitions_from_model_class(self.model) + fields_to_exclude = self.model_admin.get_form_fields_exclude(request=self.request) + panels = extract_panel_definitions_from_model_class(self.model, exclude=fields_to_exclude) edit_handler = ObjectList(panels) return edit_handler.bind_to_model(self.model)