From 35049c352aefb3ffc54ac6fb2fb1e1ee1fcb6a66 Mon Sep 17 00:00:00 2001
From: Rajeev J Sebastian <rajeev@alokin.in>
Date: Mon, 2 Apr 2018 15:51:14 +0200
Subject: [PATCH] Add request parameter to edit handlers (#4382)

---
 CHANGELOG.txt                             |  1 +
 CONTRIBUTORS.rst                          |  1 +
 docs/releases/2.1.rst                     |  1 +
 wagtail/admin/edit_handlers.py            | 14 ++--
 wagtail/admin/tests/test_edit_handlers.py | 86 +++++++++++++++++------
 wagtail/admin/views/pages.py              | 13 ++--
 wagtail/contrib/forms/tests/test_views.py | 15 +++-
 wagtail/contrib/modeladmin/views.py       |  2 +-
 wagtail/contrib/settings/views.py         |  4 +-
 wagtail/snippets/tests.py                 | 26 +++++--
 wagtail/snippets/views/snippets.py        | 12 ++--
 11 files changed, 128 insertions(+), 47 deletions(-)

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 40bbc9af65..6ae6c96a3f 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -17,6 +17,7 @@ Changelog
  * `update_index` management command now accepts a `--chunk_size` option to determine the number of items to load at once (Dave Bell)
  * Added hook `register_account_menu_item` to add new account preference items (Michael van Tellingen)
  * Added change email functionality from the account settings (Alejandro Garza, Alexs Mathilda)
+ * Add request parameter to edit handlers (Rajeev J Sebastian)
  * Fix: Status button on 'edit page' now links to the correct URL when live and draft slug differ (LB (Ben Johnston))
  * Fix: Image title text in the gallery and in the chooser now wraps for long filenames (LB (Ben Johnston), Luiz Boaretto)
  * Fix: Move image editor action buttons to the bottom of the form on mobile (Julian Gallo)
diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst
index 8d5e73e987..8dd2a46b28 100644
--- a/CONTRIBUTORS.rst
+++ b/CONTRIBUTORS.rst
@@ -289,6 +289,7 @@ Contributors
 * Mike Kamermans
 * Arthur Holzner
 * Alejandro Garza
+* Rajeev J Sebastian
 
 Translators
 ===========
diff --git a/docs/releases/2.1.rst b/docs/releases/2.1.rst
index 856ea92592..358d39f80e 100644
--- a/docs/releases/2.1.rst
+++ b/docs/releases/2.1.rst
@@ -31,6 +31,7 @@ Other features
  * ``update_index`` management command now accepts a ``--chunk_size`` option to determine the number of items to load at once (Dave Bell)
  * Added hook `register_account_menu_item` to add new account preference items (Michael van Tellingen)
  * Added change email functionality from the account settings (Alejandro Garza, Alexs Mathilda)
+ * Add request parameter to edit handlers (Rajeev J Sebastian)
 
 Bug fixes
 ~~~~~~~~~
diff --git a/wagtail/admin/edit_handlers.py b/wagtail/admin/edit_handlers.py
index c7440bdd2b..3103d43b5b 100644
--- a/wagtail/admin/edit_handlers.py
+++ b/wagtail/admin/edit_handlers.py
@@ -143,7 +143,7 @@ class EditHandler:
     def on_model_bound(self):
         pass
 
-    def bind_to_instance(self, instance=None, form=None):
+    def bind_to_instance(self, instance=None, form=None, request=None):
         new = self.bind_to_model(self.model)
 
         if not instance:
@@ -154,6 +154,10 @@ class EditHandler:
             raise ValueError("EditHandler did not receive a form object")
         new.form = form
 
+        if request is None:
+            raise ValueError("EditHandler did not receive a request object")
+        new.request = request
+
         new.on_instance_bound()
 
         return new
@@ -295,7 +299,8 @@ class BaseCompositeEditHandler(EditHandler):
                     if child.field_name not in self.form._meta.fields:
                         continue
             children.append(child.bind_to_instance(instance=self.instance,
-                                                   form=self.form))
+                                                   form=self.form,
+                                                   request=self.request))
         self.children = children
 
     def render(self):
@@ -699,7 +704,8 @@ class InlinePanel(EditHandler):
             child_edit_handler = self.get_child_edit_handler()
             self.children.append(
                 child_edit_handler.bind_to_instance(instance=subform.instance,
-                                                    form=subform))
+                                                    form=subform,
+                                                    request=self.request))
 
         # if this formset is valid, it may have been re-ordered; respect that
         # in case the parent form errored and we need to re-render
@@ -714,7 +720,7 @@ class InlinePanel(EditHandler):
 
         self.empty_child = self.get_child_edit_handler()
         self.empty_child = self.empty_child.bind_to_instance(
-            instance=empty_form.instance, form=empty_form)
+            instance=empty_form.instance, form=empty_form, request=self.request)
 
     template = "wagtailadmin/edit_handlers/inline_panel.html"
 
diff --git a/wagtail/admin/tests/test_edit_handlers.py b/wagtail/admin/tests/test_edit_handlers.py
index 4c1a039662..419c1dc31b 100644
--- a/wagtail/admin/tests/test_edit_handlers.py
+++ b/wagtail/admin/tests/test_edit_handlers.py
@@ -2,9 +2,10 @@ from datetime import date
 
 import mock
 from django import forms
+from django.contrib.auth.models import AnonymousUser
 from django.core import checks
 from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
-from django.test import TestCase, override_settings
+from django.test import RequestFactory, TestCase, override_settings
 
 from wagtail.admin.edit_handlers import (
     FieldPanel, FieldRowPanel, InlinePanel, ObjectList, PageChooserPanel, RichTextFieldPanel,
@@ -231,6 +232,10 @@ class TestExtractPanelDefinitionsFromModelClass(TestCase):
 
 class TestTabbedInterface(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         # a custom tabbed interface for EventPage
         self.event_page_tabbed_interface = TabbedInterface([
             ObjectList([
@@ -260,7 +265,8 @@ class TestTabbedInterface(TestCase):
 
         tabbed_interface = self.event_page_tabbed_interface.bind_to_instance(
             instance=event,
-            form=form
+            form=form,
+            request=self.request
         )
 
         result = tabbed_interface.render()
@@ -292,7 +298,8 @@ class TestTabbedInterface(TestCase):
 
         tabbed_interface = self.event_page_tabbed_interface.bind_to_instance(
             instance=event,
-            form=form
+            form=form,
+            request=self.request
         )
 
         result = tabbed_interface.render_form_content()
@@ -305,6 +312,9 @@ class TestTabbedInterface(TestCase):
 
 class TestObjectList(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
         # a custom ObjectList for EventPage
         self.event_page_object_list = ObjectList([
             FieldPanel('title', widget=forms.Textarea),
@@ -330,7 +340,8 @@ class TestObjectList(TestCase):
 
         object_list = self.event_page_object_list.bind_to_instance(
             instance=event,
-            form=form
+            form=form,
+            request=self.request
         )
 
         result = object_list.render()
@@ -353,6 +364,10 @@ class TestObjectList(TestCase):
 
 class TestFieldPanel(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         self.EventPageForm = get_form_for_model(
             EventPage, form_class=WagtailAdminPageForm, formsets=[])
         self.event = EventPage(title='Abergavenny sheepdog trials',
@@ -374,7 +389,8 @@ class TestFieldPanel(TestCase):
 
         field_panel = self.end_date_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_object()
 
@@ -401,7 +417,8 @@ class TestFieldPanel(TestCase):
 
         field_panel = self.end_date_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_field()
 
@@ -431,7 +448,8 @@ class TestFieldPanel(TestCase):
 
         field_panel = self.end_date_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_field()
 
@@ -441,6 +459,10 @@ class TestFieldPanel(TestCase):
 
 class TestFieldRowPanel(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         self.EventPageForm = get_form_for_model(
             EventPage, form_class=WagtailAdminPageForm, formsets=[])
         self.event = EventPage(title='Abergavenny sheepdog trials',
@@ -460,7 +482,8 @@ class TestFieldRowPanel(TestCase):
 
         field_panel = self.dates_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_object()
 
@@ -479,7 +502,8 @@ class TestFieldRowPanel(TestCase):
 
         field_panel = self.dates_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_field()
 
@@ -505,7 +529,8 @@ class TestFieldRowPanel(TestCase):
 
         field_panel = self.dates_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_field()
 
@@ -521,7 +546,8 @@ class TestFieldRowPanel(TestCase):
 
         field_panel = self.dates_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
 
         result = field_panel.render_as_field()
@@ -537,7 +563,8 @@ class TestFieldRowPanel(TestCase):
 
         field_panel = self.dates_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
 
         result = field_panel.render_as_field()
@@ -547,6 +574,10 @@ class TestFieldRowPanel(TestCase):
 
 class TestFieldRowPanelWithChooser(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         self.EventPageForm = get_form_for_model(
             EventPage, form_class=WagtailAdminPageForm, formsets=[])
         self.event = EventPage(title='Abergavenny sheepdog trials',
@@ -566,7 +597,8 @@ class TestFieldRowPanelWithChooser(TestCase):
 
         field_panel = self.dates_panel.bind_to_instance(
             instance=self.event,
-            form=form
+            form=form,
+            request=self.request
         )
         result = field_panel.render_as_object()
 
@@ -581,6 +613,10 @@ class TestPageChooserPanel(TestCase):
     fixtures = ['test.json']
 
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         model = PageChooserModel  # a model with a foreign key to Page which we want to render as a page chooser
 
         # a PageChooserPanel class that works on PageChooserModel's 'page' field
@@ -598,7 +634,7 @@ class TestPageChooserPanel(TestCase):
 
         self.form = self.PageChooserForm(instance=self.test_instance)
         self.page_chooser_panel = self.my_page_chooser_panel.bind_to_instance(
-            instance=self.test_instance, form=self.form)
+            instance=self.test_instance, form=self.form, request=self.request)
 
     def test_page_chooser_uses_correct_widget(self):
         self.assertEqual(type(self.form.fields['page'].widget), AdminPageChooser)
@@ -621,7 +657,7 @@ class TestPageChooserPanel(TestCase):
 
         form = PageChooserForm(instance=self.test_instance)
         page_chooser_panel = my_page_chooser_panel.bind_to_instance(
-            instance=self.test_instance, form=form)
+            instance=self.test_instance, form=form, request=self.request)
         result = page_chooser_panel.render_as_field()
 
         # the canChooseRoot flag on createPageChooser should now be true
@@ -646,7 +682,7 @@ class TestPageChooserPanel(TestCase):
         test_instance = PageChooserModel()
         form = self.PageChooserForm(instance=test_instance)
         page_chooser_panel = self.my_page_chooser_panel.bind_to_instance(
-            instance=test_instance, form=form)
+            instance=test_instance, form=form, request=self.request)
         result = page_chooser_panel.render_as_field()
 
         self.assertIn('<p class="help">help text</p>', result)
@@ -658,7 +694,7 @@ class TestPageChooserPanel(TestCase):
         self.assertFalse(form.is_valid())
 
         page_chooser_panel = self.my_page_chooser_panel.bind_to_instance(
-            instance=self.test_instance, form=form)
+            instance=self.test_instance, form=form, request=self.request)
         self.assertIn('<span>This field is required.</span>', page_chooser_panel.render_as_field())
 
     def test_override_page_type(self):
@@ -671,7 +707,7 @@ class TestPageChooserPanel(TestCase):
         PageChooserForm = my_page_object_list.get_form_class()
         form = PageChooserForm(instance=self.test_instance)
         page_chooser_panel = my_page_chooser_panel.bind_to_instance(
-            instance=self.test_instance, form=form)
+            instance=self.test_instance, form=form, request=self.request)
 
         result = page_chooser_panel.render_as_field()
         expected_js = 'createPageChooser("{id}", ["{model}"], {parent}, false, null);'.format(
@@ -688,7 +724,7 @@ class TestPageChooserPanel(TestCase):
         PageChooserForm = my_page_object_list.get_form_class()
         form = PageChooserForm(instance=self.test_instance)
         page_chooser_panel = my_page_chooser_panel.bind_to_instance(
-            instance=self.test_instance, form=form)
+            instance=self.test_instance, form=form, request=self.request)
 
         result = page_chooser_panel.render_as_field()
         expected_js = 'createPageChooser("{id}", ["{model}"], {parent}, false, null);'.format(
@@ -723,6 +759,11 @@ class TestPageChooserPanel(TestCase):
 class TestInlinePanel(TestCase, WagtailTestUtils):
     fixtures = ['test.json']
 
+    def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
     def test_render(self):
         """
         Check that the inline panel renders the panels set on the model
@@ -740,7 +781,8 @@ class TestInlinePanel(TestCase, WagtailTestUtils):
 
         form = EventPageForm(instance=event_page)
         panel = speaker_object_list.bind_to_instance(instance=event_page,
-                                                     form=form)
+                                                     form=form,
+                                                     request=self.request)
 
         result = panel.render_as_field()
 
@@ -795,7 +837,7 @@ class TestInlinePanel(TestCase, WagtailTestUtils):
 
         form = EventPageForm(instance=event_page)
         panel = speaker_inline_panel.bind_to_instance(
-            instance=event_page, form=form)
+            instance=event_page, form=form, request=self.request)
 
         result = panel.render_as_field()
 
@@ -852,7 +894,7 @@ class TestInlinePanel(TestCase, WagtailTestUtils):
         event_page = EventPage.objects.get(slug='christmas')
         form = EventPageForm(instance=event_page)
         panel = speaker_inline_panel.bind_to_instance(
-            instance=event_page, form=form)
+            instance=event_page, form=form, request=self.request)
 
         self.assertIn('maxForms: 1000', panel.render_js_init())
 
diff --git a/wagtail/admin/views/pages.py b/wagtail/admin/views/pages.py
index a5626bcbbe..9e7b59d8c9 100644
--- a/wagtail/admin/views/pages.py
+++ b/wagtail/admin/views/pages.py
@@ -270,12 +270,13 @@ def create(request, content_type_app_name, content_type_model_name, parent_page_
                 request, _("The page could not be created due to validation errors"), form
             )
             edit_handler = edit_handler.bind_to_instance(instance=page,
-                                                         form=form)
+                                                         form=form,
+                                                         request=request)
             has_unsaved_changes = True
     else:
         signals.init_new_page.send(sender=create, page=page, parent=parent_page)
         form = form_class(instance=page, parent_page=parent_page)
-        edit_handler = edit_handler.bind_to_instance(instance=page, form=form)
+        edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request)
         has_unsaved_changes = False
 
     return render(request, 'wagtailadmin/pages/create.html', {
@@ -470,7 +471,8 @@ def edit(request, page_id):
                 )
 
             edit_handler = edit_handler.bind_to_instance(instance=page,
-                                                         form=form)
+                                                         form=form,
+                                                         request=request)
             errors_debug = (
                 repr(edit_handler.form.errors) +
                 repr([
@@ -482,7 +484,7 @@ def edit(request, page_id):
             has_unsaved_changes = True
     else:
         form = form_class(instance=page, parent_page=parent)
-        edit_handler = edit_handler.bind_to_instance(instance=page, form=form)
+        edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request)
         has_unsaved_changes = False
 
     # Check for revisions still undergoing moderation and warn
@@ -1044,7 +1046,8 @@ def revisions_revert(request, page_id, revision_id):
 
     form = form_class(instance=revision_page)
     edit_handler = edit_handler.bind_to_instance(instance=revision_page,
-                                                 form=form)
+                                                 form=form,
+                                                 request=request)
 
     user_avatar = render_to_string('wagtailadmin/shared/user_avatar.html', {'user': revision.user})
 
diff --git a/wagtail/contrib/forms/tests/test_views.py b/wagtail/contrib/forms/tests/test_views.py
index 2bca7640d3..d8216201e2 100644
--- a/wagtail/contrib/forms/tests/test_views.py
+++ b/wagtail/contrib/forms/tests/test_views.py
@@ -2,7 +2,8 @@
 import json
 
 from django.contrib.auth import get_user_model
-from django.test import TestCase
+from django.contrib.auth.models import AnonymousUser
+from django.test import RequestFactory, TestCase
 from django.urls import reverse
 
 from wagtail.admin.edit_handlers import get_form_for_model
@@ -20,6 +21,9 @@ from wagtail.tests.utils import WagtailTestUtils
 
 class TestFormResponsesPanel(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
 
         self.form_page = make_form_page()
 
@@ -30,7 +34,7 @@ class TestFormResponsesPanel(TestCase):
         submissions_panel = FormSubmissionsPanel().bind_to_model(FormPage)
 
         self.panel = submissions_panel.bind_to_instance(
-            instance=self.form_page, form=self.FormPageForm())
+            instance=self.form_page, form=self.FormPageForm(), request=self.request)
 
     def test_render_with_submissions(self):
         """Show the panel with the count of submission and a link to the list_submissions view."""
@@ -56,6 +60,10 @@ class TestFormResponsesPanel(TestCase):
 
 class TestFormResponsesPanelWithCustomSubmissionClass(TestCase):
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         # Create a form page
         self.form_page = make_form_page_with_custom_submission()
 
@@ -69,7 +77,8 @@ class TestFormResponsesPanelWithCustomSubmissionClass(TestCase):
         submissions_panel = FormSubmissionsPanel().bind_to_model(FormPageWithCustomSubmission)
 
         self.panel = submissions_panel.bind_to_instance(self.form_page,
-                                                        self.FormPageForm())
+                                                        self.FormPageForm(),
+                                                        request=self.request)
 
     def test_render_with_submissions(self):
         """Show the panel with the count of submission and a link to the list_submissions view."""
diff --git a/wagtail/contrib/modeladmin/views.py b/wagtail/contrib/modeladmin/views.py
index 16c249ac61..3f06cbc7ed 100644
--- a/wagtail/contrib/modeladmin/views.py
+++ b/wagtail/contrib/modeladmin/views.py
@@ -138,7 +138,7 @@ class ModelFormView(WMABaseView, FormView):
         edit_handler = self.get_edit_handler()
         form = self.get_form()
         edit_handler = edit_handler.bind_to_instance(
-            instance=instance, form=form)
+            instance=instance, form=form, request=self.request)
         context = {
             'is_multipart': form.is_multipart(),
             'edit_handler': edit_handler,
diff --git a/wagtail/contrib/settings/views.py b/wagtail/contrib/settings/views.py
index 4dcf48bf97..8e2e0e54ea 100644
--- a/wagtail/contrib/settings/views.py
+++ b/wagtail/contrib/settings/views.py
@@ -74,11 +74,11 @@ def edit(request, app_name, model_name, site_pk):
         else:
             messages.error(request, _("The setting could not be saved due to errors."))
             edit_handler = edit_handler.bind_to_instance(
-                instance=instance, form=form)
+                instance=instance, form=form, request=request)
     else:
         form = form_class(instance=instance)
         edit_handler = edit_handler.bind_to_instance(
-            instance=instance, form=form)
+            instance=instance, form=form, request=request)
 
     # Show a site switcher form if there are multiple sites
     site_switcher = None
diff --git a/wagtail/snippets/tests.py b/wagtail/snippets/tests.py
index 868fd0f5ab..708a430f9e 100644
--- a/wagtail/snippets/tests.py
+++ b/wagtail/snippets/tests.py
@@ -1,10 +1,10 @@
 from django.contrib.admin.utils import quote
 from django.contrib.auth import get_user_model
-from django.contrib.auth.models import Permission
+from django.contrib.auth.models import AnonymousUser, Permission
 from django.core.exceptions import ValidationError
 from django.core.files.base import ContentFile
 from django.core.files.uploadedfile import SimpleUploadedFile
-from django.test import TestCase
+from django.test import RequestFactory, TestCase
 from django.test.utils import override_settings
 from django.urls import reverse
 from taggit.models import Tag
@@ -365,6 +365,10 @@ class TestSnippetChooserPanel(TestCase, WagtailTestUtils):
     fixtures = ['test.json']
 
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         model = SnippetChooserModel
         self.advert_text = 'Test advert text'
         test_snippet = model.objects.create(
@@ -374,7 +378,8 @@ class TestSnippetChooserPanel(TestCase, WagtailTestUtils):
         self.form_class = self.edit_handler.get_form_class()
         form = self.form_class(instance=test_snippet)
         edit_handler = self.edit_handler.bind_to_instance(instance=test_snippet,
-                                                          form=form)
+                                                          form=form,
+                                                          request=self.request)
 
         self.snippet_chooser_panel = [
             panel for panel in edit_handler.children
@@ -393,7 +398,8 @@ class TestSnippetChooserPanel(TestCase, WagtailTestUtils):
         test_snippet = SnippetChooserModel()
         form = self.form_class(instance=test_snippet)
         edit_handler = self.edit_handler.bind_to_instance(instance=test_snippet,
-                                                          form=form)
+                                                          form=form,
+                                                          request=self.request)
 
         snippet_chooser_panel = [
             panel for panel in edit_handler.children
@@ -933,6 +939,10 @@ class TestSnippetChooserPanelWithCustomPrimaryKey(TestCase, WagtailTestUtils):
     fixtures = ['test.json']
 
     def setUp(self):
+        self.request = RequestFactory().get('/')
+        user = AnonymousUser()  # technically, Anonymous users cannot access the admin
+        self.request.user = user
+
         model = SnippetChooserModelWithCustomPrimaryKey
         self.advert_text = 'Test advert text'
         test_snippet = model.objects.create(
@@ -945,7 +955,9 @@ class TestSnippetChooserPanelWithCustomPrimaryKey(TestCase, WagtailTestUtils):
         self.edit_handler = get_snippet_edit_handler(model)
         self.form_class = self.edit_handler.get_form_class()
         form = self.form_class(instance=test_snippet)
-        edit_handler = self.edit_handler.bind_to_instance(instance=test_snippet, form=form)
+        edit_handler = self.edit_handler.bind_to_instance(instance=test_snippet,
+                                                          form=form,
+                                                          request=self.request)
 
         self.snippet_chooser_panel = [
             panel for panel in edit_handler.children
@@ -963,7 +975,9 @@ class TestSnippetChooserPanelWithCustomPrimaryKey(TestCase, WagtailTestUtils):
     def test_render_as_empty_field(self):
         test_snippet = SnippetChooserModelWithCustomPrimaryKey()
         form = self.form_class(instance=test_snippet)
-        edit_handler = self.edit_handler.bind_to_instance(instance=test_snippet, form=form)
+        edit_handler = self.edit_handler.bind_to_instance(instance=test_snippet,
+                                                          form=form,
+                                                          request=self.request)
 
         snippet_chooser_panel = [
             panel for panel in edit_handler.children
diff --git a/wagtail/snippets/views/snippets.py b/wagtail/snippets/views/snippets.py
index 36a6eb9fa4..f2555e2577 100644
--- a/wagtail/snippets/views/snippets.py
+++ b/wagtail/snippets/views/snippets.py
@@ -153,11 +153,13 @@ def create(request, app_label, model_name):
         else:
             messages.error(request, _("The snippet could not be created due to errors."))
             edit_handler = edit_handler.bind_to_instance(instance=instance,
-                                                         form=form)
+                                                         form=form,
+                                                         request=request)
     else:
         form = form_class(instance=instance)
         edit_handler = edit_handler.bind_to_instance(instance=instance,
-                                                     form=form)
+                                                     form=form,
+                                                     request=request)
 
     return render(request, 'wagtailsnippets/snippets/create.html', {
         'model_opts': model._meta,
@@ -199,11 +201,13 @@ def edit(request, app_label, model_name, pk):
         else:
             messages.error(request, _("The snippet could not be saved due to errors."))
             edit_handler = edit_handler.bind_to_instance(instance=instance,
-                                                         form=form)
+                                                         form=form,
+                                                         request=request)
     else:
         form = form_class(instance=instance)
         edit_handler = edit_handler.bind_to_instance(instance=instance,
-                                                     form=form)
+                                                     form=form,
+                                                     request=request)
 
     return render(request, 'wagtailsnippets/snippets/edit.html', {
         'model_opts': model._meta,