Restore ability to use non-model fields with FieldPanel

This feature is documented in http://docs.wagtail.io/en/v1.11.1/advanced_topics/customisation/page_editing_interface.html but was broken by the EditHandler refactor #3810 - see https://github.com/wagtail/wagtail/pull/4053#issuecomment-380594092
pull/4469/merge
Matt Westcott 2018-04-11 19:15:13 +01:00
rodzic 06227a11ea
commit 63fb483efb
6 zmienionych plików z 85 dodań i 6 usunięć

Wyświetl plik

@ -7,7 +7,7 @@ from django.forms.formsets import DELETION_FIELD_NAME, ORDERING_FIELD_NAME
from django.forms.models import fields_for_model
from django.template.loader import render_to_string
from django.utils.encoding import force_text
from django.utils.functional import curry
from django.utils.functional import cached_property, curry
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy
from taggit.managers import TaggableManager
@ -511,8 +511,14 @@ class FieldPanel(EditHandler):
return [curry(comparator_class, self.db_field)]
return []
def on_model_bound(self):
self.db_field = self.model._meta.get_field(self.field_name)
@cached_property
def db_field(self):
try:
model = self.model
except AttributeError:
raise ImproperlyConfigured("%r must be bound to a model before calling db_field" % self)
return model._meta.get_field(self.field_name)
def on_instance_bound(self):
self.bound_field = self.form[self.field_name]

Wyświetl plik

@ -376,9 +376,14 @@ class TestFieldPanel(TestCase):
self.end_date_panel = (FieldPanel('date_to', classname='full-width')
.bind_to_model(EventPage))
def test_invalid_field(self):
def test_non_model_field(self):
# defining a FieldPanel for a field which isn't part of a model is OK,
# because it might be defined on the form instead
field_panel = FieldPanel('barbecue').bind_to_model(Page)
# however, accessing db_field will fail
with self.assertRaises(FieldDoesNotExist):
FieldPanel('barbecue').bind_to_model(Page)
field_panel.db_field
def test_render_as_object(self):
form = self.EventPageForm(

Wyświetl plik

@ -682,6 +682,15 @@ class TestPageCreation(TestCase, WagtailTestUtils):
self.assertContains(response, '<a href="#tab-promote" class="">Promote</a>')
self.assertContains(response, '<a href="#tab-dinosaurs" class="">Dinosaurs</a>')
def test_create_page_with_non_model_field(self):
"""
Test that additional fields defined on the form rather than the model are accepted and rendered
"""
response = self.client.get(reverse('wagtailadmin_pages:add', args=('tests', 'formclassadditionalfieldpage', self.root_page.id)))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailadmin/pages/create.html')
self.assertContains(response, "Enter SMS authentication code")
def test_create_simplepage_bad_permissions(self):
# Remove privileges from user
self.user.is_superuser = False

Wyświetl plik

@ -12,3 +12,18 @@ class ValidatedPageForm(WagtailAdminPageForm):
if value != 'bar':
raise forms.ValidationError('Field foo must be bar')
return value
class FormClassAdditionalFieldPageForm(WagtailAdminPageForm):
code = forms.CharField(
help_text='Enter SMS authentication code', max_length=5)
def clean(self):
cleaned_data = super(FormClassAdditionalFieldPageForm, self).clean()
# validate the user's code with our code check
code = cleaned_data['code']
if not code:
raise forms.ValidationError('Code is not valid')
return cleaned_data

Wyświetl plik

@ -0,0 +1,28 @@
# Generated by Django 2.0.4 on 2018-04-12 15:10
from django.db import migrations, models
import django.db.models.deletion
import wagtail.core.fields
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0040_page_draft_title'),
('tests', '0029_auto_20180215_1950'),
]
operations = [
migrations.CreateModel(
name='FormClassAdditionalFieldPage',
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')),
('location', models.CharField(max_length=255)),
('body', wagtail.core.fields.RichTextField(blank=True)),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
]

Wyświetl plik

@ -39,7 +39,7 @@ from wagtail.search import index
from wagtail.snippets.edit_handlers import SnippetChooserPanel
from wagtail.snippets.models import register_snippet
from .forms import ValidatedPageForm
from .forms import FormClassAdditionalFieldPageForm, ValidatedPageForm
from .views import CustomSubmissionsListView
EVENT_AUDIENCE_CHOICES = (
@ -314,6 +314,22 @@ class HeadCountRelatedModelUsingPK(models.Model):
panels = [FieldPanel('head_count')]
# Override the standard WagtailAdminPageForm to add field that is not in model
# so that we can test additional potential issues like comparing versions
class FormClassAdditionalFieldPage(Page):
location = models.CharField(max_length=255)
body = RichTextField(blank=True)
content_panels = [
FieldPanel('title', classname="full title"),
FieldPanel('location'),
FieldPanel('body'),
FieldPanel('code'), # not in model, see set base_form_class
]
base_form_class = FormClassAdditionalFieldPageForm
# Just to be able to test multi table inheritance
class SingleEventPage(EventPage):
excerpt = models.TextField(