1
From: Preston Timmons <prestontimmons@gfa.org>
2
Origin: https://github.com/django/django/pull/2601/
3
Last-Updated: 2014-06-22
4
Subject: Fixed #22486: Reverse raises AttributeError on partial functions.
6
Create the lookup_str from the original function whenever a partial
7
is provided as an argument to a url pattern.
9
django/core/urlresolvers.py | 4 ++++
10
tests/urlpatterns_reverse/urls.py | 6 +++++-
11
tests/urlpatterns_reverse/views.py | 10 ++++++++++
12
3 files changed, 19 insertions(+), 1 deletion(-)
14
--- a/django/core/urlresolvers.py
15
+++ b/django/core/urlresolvers.py
18
from threading import local
22
from django.http import Http404
23
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
24
from django.utils.datastructures import MultiValueDict
26
self._callback_strs.add(pattern._callback_str)
27
elif hasattr(pattern, '_callback'):
28
callback = pattern._callback
29
+ if isinstance(callback, functools.partial):
30
+ callback = callback.func
32
if not hasattr(callback, '__name__'):
33
lookup_str = callback.__module__ + "." + callback.__class__.__name__
35
--- a/tests/urlpatterns_reverse/urls.py
36
+++ b/tests/urlpatterns_reverse/urls.py
39
from django.conf.urls import patterns, url, include
41
-from .views import empty_view, absolute_kwargs_view
42
+from .views import empty_view, empty_view_partial, empty_view_wrapped, absolute_kwargs_view
45
other_patterns = patterns('',
47
include('urlpatterns_reverse.included_urls')),
48
url('', include('urlpatterns_reverse.extra_urls')),
50
+ # Partials should be fine.
51
+ url(r'^partial/', empty_view_partial, name="partial"),
52
+ url(r'^partial_wrapped/', empty_view_wrapped, name="partial_wrapped"),
54
# This is non-reversible, but we shouldn't blow up when parsing it.
55
url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"),
57
--- a/tests/urlpatterns_reverse/views.py
58
+++ b/tests/urlpatterns_reverse/views.py
60
+from functools import partial, update_wrapper
62
from django.http import HttpResponse
63
from django.views.generic import RedirectView
64
from django.core.urlresolvers import reverse_lazy
67
def bad_view(request, *args, **kwargs):
68
raise ValueError("I don't think I'm getting good value for this view")
71
+empty_view_partial = partial(empty_view, template_name="template.html")
74
+empty_view_wrapped = update_wrapper(
75
+ partial(empty_view, template_name="template.html"), empty_view,