Add a dont_use_model_field_default_for_empty_data flag to BlockWidget to stop Django 1.10.1 from skipping it

Fixes #2994 for Django 1.10.1 ONLY.
This commit is contained in:
Matt Westcott 2016-09-21 14:18:21 +01:00
parent 0c1b67bc16
commit bb1ae7551f
4 changed files with 84 additions and 0 deletions

View file

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.1 on 2016-09-21 11:37
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import wagtail.wagtailcore.blocks
import wagtail.wagtailcore.fields
import wagtail.wagtailimages.blocks
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0030_index_on_pagerevision_created_at'),
('tests', '0008_inlinestreampage_inlinestreampagesection'),
]
operations = [
migrations.CreateModel(
name='DefaultStreamPage',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
('body', wagtail.wagtailcore.fields.StreamField((('text', wagtail.wagtailcore.blocks.CharBlock()), ('rich_text', wagtail.wagtailcore.blocks.RichTextBlock()), ('image', wagtail.wagtailimages.blocks.ImageChooserBlock())), default='')),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
]

View file

@ -556,6 +556,19 @@ class StreamPage(Page):
]
class DefaultStreamPage(Page):
body = StreamField([
('text', CharBlock()),
('rich_text', RichTextBlock()),
('image', ImageChooserBlock()),
], default='')
content_panels = [
FieldPanel('title'),
StreamFieldPanel('body'),
]
class MTIBasePage(Page):
is_creatable = False

View file

@ -21,6 +21,7 @@ from django.utils.dateparse import parse_date
from wagtail.tests.testapp.models import (
EVENT_AUDIENCE_CHOICES, Advert, AdvertPlacement, BusinessChild, BusinessIndex, BusinessSubIndex,
DefaultStreamPage,
EventPage, EventPageCarouselItem, FilePage, SimplePage, SingleEventPage, SingletonPage,
StandardChild, StandardIndex, TaggedPage)
from wagtail.tests.utils import WagtailTestUtils
@ -3511,3 +3512,36 @@ class TestRecentEditsPanel(TestCase, WagtailTestUtils):
# Alice's dashboard should still list that first edit
response = self.go_to_dashboard_response()
self.assertIn('Your most recent edits', response.content.decode('utf-8'))
class TestIssue2994(TestCase, WagtailTestUtils):
"""
When submitting the add/edit page form, Django 1.10.1 fails to update StreamFields
that have a default value, because it notices the lack of postdata field
with a name exactly matching the field name and wrongly assumes that the field has
been omitted from the form. To avoid this in Django 1.10.1, we need to set
dont_use_model_field_default_for_empty_data=True on the widget; in Django >=1.10.2,
we need to provide a custom value_omitted_from_data method.
"""
def setUp(self):
self.root_page = Page.objects.get(id=2)
self.user = self.login()
def test_page_edit_post_publish_url(self):
# Post
post_data = {
'title': "Issue 2994 test",
'slug': 'issue-2994-test',
'body-count': '1',
'body-0-deleted': '',
'body-0-order': '0',
'body-0-type': 'text',
'body-0-value': 'hello world',
'action-publish': "Publish",
}
self.client.post(
reverse('wagtailadmin_pages:add', args=('tests', 'defaultstreampage', self.root_page.id)), post_data
)
new_page = DefaultStreamPage.objects.get(slug='issue-2994-test')
self.assertEqual(1, len(new_page.body))
self.assertEqual('hello world', new_page.body[0].value)

View file

@ -559,6 +559,12 @@ class DeclarativeSubBlocksMetaclass(BaseBlock):
class BlockWidget(forms.Widget):
"""Wraps a block object as a widget so that it can be incorporated into a Django form"""
# Flag used by Django 1.10.1 (only) to indicate that this widget will not necessarily submit
# a postdata item with a name that matches the field name -
# see https://github.com/django/django/pull/7068, https://github.com/torchbox/wagtail/issues/2994
dont_use_model_field_default_for_empty_data = True
def __init__(self, block_def, attrs=None):
super(BlockWidget, self).__init__(attrs=attrs)
self.block_def = block_def