Commit d7e81275 authored by Jacob Kaplan-Moss's avatar Jacob Kaplan-Moss
Browse files

Fixed #10194: added `django.shortcuts.redirect`, a do-what-I-mean redirect...

Fixed #10194: added `django.shortcuts.redirect`, a do-what-I-mean redirect shortcut. See the docs at topics/http/shortcuts for details.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10108 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 4eadcf45
Loading
Loading
Loading
Loading
+40 −1
Original line number Diff line number Diff line
@@ -6,8 +6,10 @@ for convenience's sake.

from django.template import loader
from django.http import HttpResponse, Http404
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.core import urlresolvers

def render_to_response(*args, **kwargs):
    """
@@ -17,6 +19,43 @@ def render_to_response(*args, **kwargs):
    httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
    return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)

def redirect(to, *args, **kwargs):
    """
    Returns an HttpResponseRedirect to the apropriate URL for the arguments
    passed.
    
    The arguments could be:
    
        * A model: the model's `get_absolute_url()` function will be called.
    
        * A view name, possibly with arguments: `urlresolvers.reverse()` will
          be used to reverse-resolve the name.
         
        * A URL, which will be used as-is for the redirect location.
        
    By default issues a temporary redirect; pass permanent=True to issue a
    permanent redirect
    """
    if kwargs.pop('permanent', False):
        redirect_class = HttpResponsePermanentRedirect
    else:
        redirect_class = HttpResponseRedirect
    
    # If it's a model, use get_absolute_url()
    if hasattr(to, 'get_absolute_url'):
        return redirect_class(to.get_absolute_url())
    
    # Next try a reverse URL resolution.
    try:
        return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs))
    except urlresolvers.NoReverseMatch:
        # If this doesn't "feel" like a URL, re-raise.
        if '/' not in to and '.' not in to:
            raise
        
    # Finally, fall back and assume it's a URL
    return redirect_class(to)

def _get_queryset(klass):
    """
    Returns a QuerySet from a Model, Manager, or QuerySet. Created to make
+87 −14
Original line number Diff line number Diff line
@@ -4,16 +4,23 @@
Django shortcut functions
=========================

.. module:: django.shortcuts
   :synopsis:
       Convience shortcuts that spam multiple levels of Django's MVC stack.

.. index:: shortcuts

The package ``django.shortcuts`` collects helper functions and classes that
"span" multiple levels of MVC. In other words, these functions/classes
introduce controlled coupling for convenience's sake.

``render_to_response()``
========================
``render_to_response``
======================

``django.shortcuts.render_to_response`` renders a given template with a given
context dictionary and returns an ``HttpResponse`` object with that rendered
text.
.. function:: render_to_response(template[, dictionary][, context_instance][, mimetype])

   Renders a given template with a given context dictionary and returns an
   :class:`~django.http.HttpResponse` object with that rendered text.

Required arguments
------------------
@@ -42,7 +49,6 @@ Optional arguments
                                  context_instance=RequestContext(request))

``mimetype``

    .. versionadded:: 1.0 
    
    The MIME type to use for the resulting document. Defaults to the value of
@@ -73,12 +79,77 @@ This example is equivalent to::
        r = HttpResponse(t.render(c),
            mimetype="application/xhtml+xml")

``redirect``
============

.. function:: redirect(to[, permanent=False], *args, **kwargs)

   Returns an HttpResponseRedirect to the apropriate URL for the arguments
   passed.
   
   The arguments could be:
   
       * A model: the model's `get_absolute_url()` function will be called.
   
       * A view name, possibly with arguments: `urlresolvers.reverse()` will
         be used to reverse-resolve the name.
        
       * A URL, which will be used as-is for the redirect location.
       
   By default issues a temporary redirect; pass permanent=True to issue a
   permanent redirect
   
Examples
--------

You can use the :func:`redirect` function in a number of ways.

    1. By passing some object; that object's
       :meth:`~django.db.models.Model.get_absolute_url` method will be called
       to figure out the redirect URL::
       
            def my_view(request):
                ...
                object = MyModel.objects.get(...)
                return redirect(object)
                
    2. By passing the name of a view and optionally some positional or
       keyword arguments; the URL will be reverse resolved using the
       :func:`~django.core.urlresolvers.reverse` method::
       
            def my_view(request):
                ...
                return redirect('some-view-name', foo='bar')
                
    3. By passing a hardcoded URL to redirect to::
    
            def my_view(request):
                ...
                return redirect('/some/url/')
                
       This also works with full URLs::
       
            def my_view(request):
                ...
                return redirect('http://example.com/')
                
By default, :func:`redirect` returns a temporary redirect. All of the above
forms accept a ``permanent`` argument; if set to ``True`` a permanent redirect
will be returned::

    def my_view(request):
        ...
        object = MyModel.objects.get(...)
        return redirect(object, permanent=True)

``get_object_or_404``
=====================

``django.shortcuts.get_object_or_404`` calls
:meth:`~django.db.models.QuerySet.get()` on a given model manager, but it raises
``django.http.Http404`` instead of the model's ``DoesNotExist`` exception.
.. function:: get_object_or_404(object, *args, **kwargs)

   Calls :meth:`~django.db.models.QuerySet.get()` on a given model manager,
   but it raises ``django.http.Http404`` instead of the model's
   ``DoesNotExist`` exception.

Required arguments
------------------
@@ -118,9 +189,11 @@ raised if more than one object is found.
``get_list_or_404``
===================

``django.shortcuts.get_list_or_404`` returns the result of
:meth:`~django.db.models.QuerySet.filter()` on a given model manager, raising
``django.http.Http404`` if the resulting list is empty.
.. function:: get_list_or_404(klass, *args, **kwargs)

   Returns the result of :meth:`~django.db.models.QuerySet.filter()` on a
   given model manager, raising ``django.http.Http404`` if the resulting list
   is empty.

Required arguments
------------------
+33 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ Unit tests for reverse URL lookups.
"""

from django.core.urlresolvers import reverse, NoReverseMatch
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.shortcuts import redirect
from django.test import TestCase

test_data = (
@@ -97,3 +99,34 @@ class URLPatternReverse(TestCase):
            else:
                self.assertEquals(got, expected)

class ReverseShortcutTests(TestCase):
    urls = 'regressiontests.urlpatterns_reverse.urls'
    
    def test_redirect_to_object(self):
        # We don't really need a model; just something with a get_absolute_url
        class FakeObj(object):
            def get_absolute_url(self):
                return "/hi-there/"
                
        res = redirect(FakeObj())
        self.assert_(isinstance(res, HttpResponseRedirect))
        self.assertEqual(res['Location'], '/hi-there/')
        
        res = redirect(FakeObj(), permanent=True)
        self.assert_(isinstance(res, HttpResponsePermanentRedirect))
        self.assertEqual(res['Location'], '/hi-there/')
        
    def test_redirect_to_view_name(self):
        res = redirect('hardcoded2')
        self.assertEqual(res['Location'], '/hardcoded/doc.pdf')
        res = redirect('places', 1)
        self.assertEqual(res['Location'], '/places/1/')
        res = redirect('headlines', year='2008', month='02', day='17')
        self.assertEqual(res['Location'], '/headlines/2008.02.17/')
        self.assertRaises(NoReverseMatch, redirect, 'not-a-view')
        
    def test_redirect_to_url(self):
        res = redirect('/foo/')
        self.assertEqual(res['Location'], '/foo/')
        res = redirect('http://example.com/')
        self.assertEqual(res['Location'], 'http://example.com/')
 No newline at end of file