From ffdbe3e26c068350e984d67bf04326baaa0d193e Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Wed, 23 Oct 2019 10:52:56 +0100 Subject: [PATCH] Avoid calling versioned_static from static form media definitions (#5644) * Avoid calling versioned_static from static form media definitions Fixes #5632 Defining media definitions with `class Media:` means that those lines are evaluated on application startup; this means that they cannot contain calls to the Django static file finder, because ManifestStaticFilesStorage doesn't work until collectstatic has completed. Fix this by making those definitions into `def media(self):` methods. * Add test to confirm that inheritance still works with dynamic form media definitions --- wagtail/admin/rich_text/editors/hallo.py | 12 +++++++--- wagtail/admin/tests/test_widgets.py | 11 +++++++++ wagtail/admin/widgets.py | 29 ++++++++++++++++-------- wagtail/contrib/settings/forms.py | 7 +++--- wagtail/documents/widgets.py | 8 ++++--- wagtail/images/widgets.py | 8 ++++--- wagtail/snippets/widgets.py | 8 ++++--- wagtail/tests/testapp/forms.py | 8 +++++++ 8 files changed, 67 insertions(+), 24 deletions(-) diff --git a/wagtail/admin/rich_text/editors/hallo.py b/wagtail/admin/rich_text/editors/hallo.py index f06a7e8e7..c6d422587 100644 --- a/wagtail/admin/rich_text/editors/hallo.py +++ b/wagtail/admin/rich_text/editors/hallo.py @@ -68,12 +68,18 @@ class HalloListPlugin(HalloPlugin): plugins[self.name]['lists'][self.list_type] = True +class HalloRequireParagraphsPlugin(HalloPlugin): + @property + def media(self): + return Media(js=[ + versioned_static('wagtailadmin/js/hallo-plugins/hallo-requireparagraphs.js'), + ]) + super().media + + # Plugins which are always imported, and cannot be enabled/disabled via 'features' CORE_HALLO_PLUGINS = [ HalloPlugin(name='halloreundo', order=50), - HalloPlugin(name='hallorequireparagraphs', js=[ - versioned_static('wagtailadmin/js/hallo-plugins/hallo-requireparagraphs.js'), - ]), + HalloRequireParagraphsPlugin(name='hallorequireparagraphs'), HalloHeadingPlugin(element='p') ] diff --git a/wagtail/admin/tests/test_widgets.py b/wagtail/admin/tests/test_widgets.py index aca71d283..75a507bf7 100644 --- a/wagtail/admin/tests/test_widgets.py +++ b/wagtail/admin/tests/test_widgets.py @@ -3,6 +3,7 @@ from django.test.utils import override_settings from wagtail.admin import widgets from wagtail.core.models import Page +from wagtail.tests.testapp.forms import AdminStarDateInput from wagtail.tests.testapp.models import EventPage, SimplePage @@ -122,6 +123,16 @@ class TestAdminDateInput(TestCase): html, ) + def test_media_inheritance(self): + """ + Widgets inheriting from AdminDateInput should have their media definitions merged + with AdminDateInput's + """ + widget = AdminStarDateInput() + media_html = str(widget.media) + self.assertIn('wagtailadmin/js/date-time-chooser.js', media_html) + self.assertIn('vendor/star_date.js', media_html) + class TestAdminDateTimeInput(TestCase): diff --git a/wagtail/admin/widgets.py b/wagtail/admin/widgets.py index 7379e514f..0a758d330 100644 --- a/wagtail/admin/widgets.py +++ b/wagtail/admin/widgets.py @@ -2,6 +2,7 @@ import itertools import json from functools import total_ordering +from django import forms from django.conf import settings from django.forms import widgets from django.forms.utils import flatatt @@ -59,8 +60,11 @@ class AdminDateInput(widgets.DateInput): return context - class Media: - js = [versioned_static('wagtailadmin/js/date-time-chooser.js')] + @property + def media(self): + return forms.Media(js=[ + versioned_static('wagtailadmin/js/date-time-chooser.js'), + ]) class AdminTimeInput(widgets.TimeInput): @@ -72,8 +76,11 @@ class AdminTimeInput(widgets.TimeInput): default_attrs.update(attrs) super().__init__(attrs=default_attrs, format=format) - class Media: - js = [versioned_static('wagtailadmin/js/date-time-chooser.js')] + @property + def media(self): + return forms.Media(js=[ + versioned_static('wagtailadmin/js/date-time-chooser.js'), + ]) class AdminDateTimeInput(widgets.DateTimeInput): @@ -100,8 +107,11 @@ class AdminDateTimeInput(widgets.DateTimeInput): return context - class Media: - js = [versioned_static('wagtailadmin/js/date-time-chooser.js')] + @property + def media(self): + return forms.Media(js=[ + versioned_static('wagtailadmin/js/date-time-chooser.js'), + ]) class AdminTagWidget(TagWidget): @@ -238,11 +248,12 @@ class AdminPageChooser(AdminChooser): user_perms=json.dumps(self.user_perms), ) - class Media: - js = [ + @property + def media(self): + return forms.Media(js=[ versioned_static('wagtailadmin/js/page-chooser-modal.js'), versioned_static('wagtailadmin/js/page-chooser.js'), - ] + ]) @total_ordering diff --git a/wagtail/contrib/settings/forms.py b/wagtail/contrib/settings/forms.py index 5c3f94380..35c60c8a4 100644 --- a/wagtail/contrib/settings/forms.py +++ b/wagtail/contrib/settings/forms.py @@ -8,10 +8,11 @@ from wagtail.core.models import Site class SiteSwitchForm(forms.Form): site = forms.ChoiceField(choices=[]) - class Media: - js = [ + @property + def media(self): + return forms.Media(js=[ versioned_static('wagtailsettings/js/site-switcher.js'), - ] + ]) def __init__(self, current_site, model, **kwargs): initial_data = {'site': self.get_change_url(current_site, model)} diff --git a/wagtail/documents/widgets.py b/wagtail/documents/widgets.py index adf4d9715..d496e379c 100644 --- a/wagtail/documents/widgets.py +++ b/wagtail/documents/widgets.py @@ -1,5 +1,6 @@ import json +from django import forms from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -32,8 +33,9 @@ class AdminDocumentChooser(AdminChooser): def render_js_init(self, id_, name, value): return "createDocumentChooser({0});".format(json.dumps(id_)) - class Media: - js = [ + @property + def media(self): + return forms.Media(js=[ versioned_static('wagtaildocs/js/document-chooser-modal.js'), versioned_static('wagtaildocs/js/document-chooser.js'), - ] + ]) diff --git a/wagtail/images/widgets.py b/wagtail/images/widgets.py index bd8f8712d..76518a8ca 100644 --- a/wagtail/images/widgets.py +++ b/wagtail/images/widgets.py @@ -1,5 +1,6 @@ import json +from django import forms from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -32,8 +33,9 @@ class AdminImageChooser(AdminChooser): def render_js_init(self, id_, name, value): return "createImageChooser({0});".format(json.dumps(id_)) - class Media: - js = [ + @property + def media(self): + return forms.Media(js=[ versioned_static('wagtailimages/js/image-chooser-modal.js'), versioned_static('wagtailimages/js/image-chooser.js'), - ] + ]) diff --git a/wagtail/snippets/widgets.py b/wagtail/snippets/widgets.py index 37ec46b77..23aca86ef 100644 --- a/wagtail/snippets/widgets.py +++ b/wagtail/snippets/widgets.py @@ -1,5 +1,6 @@ import json +from django import forms from django.template.loader import render_to_string from django.utils.translation import ugettext_lazy as _ @@ -41,8 +42,9 @@ class AdminSnippetChooser(AdminChooser): app=model._meta.app_label, model=model._meta.model_name))) - class Media: - js = [ + @property + def media(self): + return forms.Media(js=[ versioned_static('wagtailsnippets/js/snippet-chooser-modal.js'), versioned_static('wagtailsnippets/js/snippet-chooser.js'), - ] + ]) diff --git a/wagtail/tests/testapp/forms.py b/wagtail/tests/testapp/forms.py index 33e74a1a6..3cd1eb2ca 100644 --- a/wagtail/tests/testapp/forms.py +++ b/wagtail/tests/testapp/forms.py @@ -1,6 +1,7 @@ from django import forms from wagtail.admin.forms import WagtailAdminPageForm +from wagtail.admin.widgets import AdminDateInput class ValidatedPageForm(WagtailAdminPageForm): @@ -27,3 +28,10 @@ class FormClassAdditionalFieldPageForm(WagtailAdminPageForm): raise forms.ValidationError('Code is not valid') return cleaned_data + + +class AdminStarDateInput(AdminDateInput): + # Media definitions defined as `class Media:` should be merged into + # the media of the parent class + class Media: + js = ['vendor/star_date.js']