Description: Restored the ability to reverse views created using functools.partial
Origin: upstream, https://github.com/django/django/commit/b91c385e324f1cb94d20e2ad146372c259d51d3b
Bug: https://code.djangoproject.com/ticket/22486
Bug-Ubuntu: https://bugs.launchpad.net/debian/+source/python-django/+bug/1311433
Forwarded: not-needed
Last-Update: 2014-05-09

--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -7,6 +7,7 @@
     (view_function, function_args, function_kwargs)
 """
 
+import functools
 import re
 
 from django.http import Http404
@@ -168,6 +169,9 @@
                 self._callback_strs.add(pattern._callback_str)
             elif hasattr(pattern, '_callback'):
                 callback = pattern._callback
+                if isinstance(callback, functools.partial):
+                    callback = callback.func
+
                 if not hasattr(callback, '__name__'):
                     lookup_str = callback.__module__ + "." + callback.__class__.__name__
                 else:
--- a/tests/regressiontests/urlpatterns_reverse/urls.py
+++ b/tests/regressiontests/urlpatterns_reverse/urls.py
@@ -1,5 +1,5 @@
 from django.conf.urls.defaults import *
-from views import empty_view, absolute_kwargs_view
+from views import empty_view, empty_view_partial, empty_view_wrapped, absolute_kwargs_view
 
 other_patterns = patterns('',
     url(r'non_path_include/$', empty_view, name='non_path_include'),
@@ -48,6 +48,10 @@
             include('regressiontests.urlpatterns_reverse.included_urls')),
     url('', include('regressiontests.urlpatterns_reverse.extra_urls')),
 
+    # Partials should be fine.
+    url(r'^partial/', empty_view_partial, name="partial"),
+    url(r'^partial_wrapped/', empty_view_wrapped, name="partial_wrapped"),
+
     # This is non-reversible, but we shouldn't blow up when parsing it.
     url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"),
 
--- a/tests/regressiontests/urlpatterns_reverse/views.py
+++ b/tests/regressiontests/urlpatterns_reverse/views.py
@@ -1,3 +1,5 @@
+from functools import partial, update_wrapper
+
 def empty_view(request, *args, **kwargs):
     pass
 
@@ -7,5 +9,13 @@
 def absolute_kwargs_view(request, arg1=1, arg2=2):
     pass
 
+
+empty_view_partial = partial(empty_view, template_name="template.html")
+
+
+empty_view_wrapped = update_wrapper(
+    partial(empty_view, template_name="template.html"), empty_view,
+)
+
 def nested_view(request):
     pass
