Add a dummy_request method to Page so that we can generate page previews without passing in the active request object (which may have undesirable side effects, e.g. may be a POST)

This commit is contained in:
Matt Westcott 2014-04-07 20:08:33 +01:00
parent f971b24f96
commit f0aee82906
2 changed files with 54 additions and 9 deletions

View file

@ -340,12 +340,14 @@ def preview_on_edit(request, page_id):
if form.is_valid():
form.save(commit=False)
# FIXME: passing the original request to page.serve is dodgy (particularly if page.serve has
# special treatment of POSTs). Ought to construct one that more or less matches what would be sent
# as a front-end GET request
# This view will generally be invoked as an AJAX request; as such, in the case of
# an error Django will return a plaintext response. This isn't what we want, since
# we will be writing the response back to an HTML page regardless of success or
# failure - as such, we strip out the X-Requested-With header to get Django to return
# an HTML error response
request.META.pop('HTTP_X_REQUESTED_WITH', None)
request.META.pop('HTTP_X_REQUESTED_WITH', None) # Make this request appear to the page's serve method as a non-ajax one, as they will often implement custom behaviour for XHR
response = page.serve(request)
response = page.serve(page.dummy_request())
response['X-Wagtail-Preview'] = 'ok'
return response
@ -380,10 +382,14 @@ def preview_on_create(request, content_type_app_name, content_type_model_name, p
if form.is_valid():
form.save(commit=False)
# FIXME: passing the original request to page.serve is dodgy (particularly if page.serve has
# special treatment of POSTs). Ought to construct one that more or less matches what would be sent
# as a front-end GET request
response = page.serve(request)
# This view will generally be invoked as an AJAX request; as such, in the case of
# an error Django will return a plaintext response. This isn't what we want, since
# we will be writing the response back to an HTML page regardless of success or
# failure - as such, we strip out the X-Requested-With header to get Django to return
# an HTML error response
request.META.pop('HTTP_X_REQUESTED_WITH', None)
response = page.serve(page.dummy_request())
response['X-Wagtail-Preview'] = 'ok'
return response

View file

@ -1,5 +1,7 @@
import sys
import os
from StringIO import StringIO
from urlparse import urlparse
from modelcluster.models import ClusterableModel
@ -7,6 +9,8 @@ from django.db import models, connection, transaction
from django.db.models import get_model, Q
from django.http import Http404
from django.core.cache import cache
from django.core.handlers.wsgi import WSGIRequest
from django.core.handlers.base import BaseHandler
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Group
from django.conf import settings
@ -501,6 +505,41 @@ class Page(MP_Node, ClusterableModel, Indexed):
user_perms = UserPagePermissionsProxy(user)
return user_perms.for_page(self)
def dummy_request(self):
"""
Construct a HttpRequest object that is, as far as possible, representative of ones that would
receive this page as a response. Used for previewing / moderation and any other place where we
want to display a view of this page in the admin interface without going through the regular
page routing logic.
"""
url = self.full_url
if url:
url_info = urlparse(url)
hostname = url_info.netloc
path = url_info.path
port = url_info.port or 80
else:
hostname = 'example.com'
path = '/'
port = 80
request = WSGIRequest({
'REQUEST_METHOD': 'GET',
'PATH_INFO': path,
'SERVER_NAME': hostname,
'SERVER_PORT': port,
'wsgi.input': StringIO(),
})
# Apply middleware to the request - see http://www.mellowmorning.com/2011/04/18/mock-django-request-for-testing/
handler = BaseHandler()
handler.load_middleware()
for middleware_method in handler._request_middleware:
if middleware_method(request):
raise Exception("Couldn't create request mock object - "
"request middleware returned a response")
return request
def get_navigation_menu_items():
# Get all pages that appear in the navigation menu: ones which have children,