diff --git a/CHANGES b/CHANGES index 3b77329f..24a6162e 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,8 @@ Release date to be announced, codename to be decided. - the endpoint for the :meth:`flask.Module.add_url_rule` method is now optional to be consistent with the function of the same name on the application object. +- added a :func:`flask.make_response` function that simplifies + creating response object instances in views. Version 0.5.2 ------------- diff --git a/docs/api.rst b/docs/api.rst index d7f887e4..f31563b4 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -228,6 +228,8 @@ Useful Functions and Classes .. autofunction:: redirect +.. autofunction:: make_response + .. autofunction:: send_file .. autofunction:: send_from_directory diff --git a/flask/__init__.py b/flask/__init__.py index f4617271..93ada5f7 100644 --- a/flask/__init__.py +++ b/flask/__init__.py @@ -19,7 +19,7 @@ from .app import Flask, Request, Response from .config import Config from .helpers import url_for, jsonify, json_available, flash, \ send_file, send_from_directory, get_flashed_messages, \ - get_template_attribute + get_template_attribute, make_response from .globals import current_app, g, request, session, _request_ctx_stack from .module import Module from .templating import render_template, render_template_string diff --git a/flask/helpers.py b/flask/helpers.py index fc309e67..6b57420c 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -101,6 +101,48 @@ def jsonify(*args, **kwargs): indent=None if request.is_xhr else 2), mimetype='application/json') +def make_response(*args): + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html', 404)) + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + def url_for(endpoint, **values): """Generates a URL to the given endpoint with the method provided. The endpoint is relative to the active module if modules are in use. diff --git a/tests/flask_tests.py b/tests/flask_tests.py index f2451223..ccf9b871 100644 --- a/tests/flask_tests.py +++ b/tests/flask_tests.py @@ -393,6 +393,24 @@ class BasicFunctionalityTestCase(unittest.TestCase): assert rv.status_code == 400 assert rv.mimetype == 'text/plain' + def test_make_response(self): + app = flask.Flask(__name__) + with app.test_request_context(): + rv = flask.make_response() + assert rv.status_code == 200 + assert rv.data == '' + assert rv.mimetype == 'text/html' + + rv = flask.make_response('Awesome') + assert rv.status_code == 200 + assert rv.data == 'Awesome' + assert rv.mimetype == 'text/html' + + rv = flask.make_response('W00t', 404) + assert rv.status_code == 404 + assert rv.data == 'W00t' + assert rv.mimetype == 'text/html' + def test_url_generation(self): app = flask.Flask(__name__) @app.route('/hello/', methods=['POST'])