Simplifies & optimizes preview data storage.

This also makes previewing more robust:
- when users go directly to the preview URL for a page they never previewed;
- when there’s a validation error using stored data.
This commit is contained in:
Bertrand Bordage 2017-05-03 23:05:07 +02:00
parent d37838711b
commit 51d85e6f1f

View file

@ -2,7 +2,7 @@ from __future__ import absolute_import, unicode_literals
from time import time
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.urlresolvers import reverse
from django.db.models import Count
from django.http import Http404, HttpResponse, JsonResponse
@ -12,6 +12,7 @@ from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.http import is_safe_url, urlquote
from django.utils.safestring import mark_safe
from django.utils.six import string_types
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_GET, require_POST
from django.views.decorators.vary import vary_on_headers
@ -578,50 +579,44 @@ class PreviewOnEdit(View):
return get_object_or_404(Page,
id=self.args[0]).get_latest_revision_as_page()
def get_form(self):
page = self.get_page()
def get_form(self, page, query_dict):
form_class = page.get_edit_handler().get_form_class(page._meta.model)
parent_page = page.get_parent().specific
post_data_dict, timestamp = self.request.session[self.session_key]
return form_class(query_dict, instance=page, parent_page=parent_page)
# convert post_data_dict back into a QueryDict
post_data = QueryDict('', mutable=True)
for k, v in post_data_dict.items():
post_data.setlist(k, v)
return form_class(post_data, instance=page, parent_page=parent_page)
@staticmethod
def is_form_valid(form):
try:
return form.is_valid()
except ValidationError:
return False
def post(self, request, *args, **kwargs):
# TODO: Handle request.FILES.
# Convert request.POST to a plain dict (rather than a QueryDict) so that it can be
# stored without data loss in session data
post_data_dict = dict(request.POST.lists())
request.session[self.session_key] = post_data_dict, time()
request.session[self.session_key] = request.POST.urlencode(), time()
self.remove_old_preview_data()
form = self.get_form()
return JsonResponse({'is_valid': form.is_valid()})
form = self.get_form(self.get_page(), request.POST)
return JsonResponse({'is_valid': self.is_form_valid(form)})
def error_response(self, page):
return render(self.request, 'wagtailadmin/pages/preview_error.html',
{'page': page})
def get(self, request, *args, **kwargs):
# Receive the form submission that would typically be posted
# to the view. If submission is valid, return the rendered page;
# if not, re-render the edit form
form = self.get_form()
page = form.instance
page = self.get_page()
if form.is_valid():
form.save(commit=False)
post_data, timestamp = self.request.session.get(self.session_key)
if not isinstance(post_data, string_types):
post_data = ''
form = self.get_form(page, QueryDict(post_data))
preview_mode = request.GET.get('mode', page.default_preview_mode)
return page.serve_preview(page.dummy_request(request),
preview_mode)
if not self.is_form_valid(form):
return self.error_response(page)
return self.error_response(page)
form.save(commit=False)
preview_mode = request.GET.get('mode', page.default_preview_mode)
return page.serve_preview(page.dummy_request(request),
preview_mode)
class PreviewOnCreate(PreviewOnEdit):
@ -651,7 +646,7 @@ class PreviewOnCreate(PreviewOnEdit):
def get_form(self):
form = super(PreviewOnCreate, self).get_form()
if form.is_valid():
if self.is_form_valid(form):
# Ensures our unsaved page has a suitable url.
form.instance.set_url_path(form.parent_page)