1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
From: Preston Timmons <prestontimmons@gfa.org>
Origin: https://github.com/django/django/pull/2601/
Last-Updated: 2014-06-22
Subject: Fixed #22486: Reverse raises AttributeError on partial functions.
Create the lookup_str from the original function whenever a partial
is provided as an argument to a url pattern.
---
django/core/urlresolvers.py | 4 ++++
tests/urlpatterns_reverse/urls.py | 6 +++++-
tests/urlpatterns_reverse/views.py | 10 ++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -8,6 +8,7 @@
"""
import re
+import functools
from threading import local
from django.http import Http404
@@ -248,6 +249,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
@@ -2,7 +2,7 @@
from django.conf.urls import patterns, url, include
-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('',
@@ -53,6 +53,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
+
from django.http import HttpResponse
from django.views.generic import RedirectView
from django.core.urlresolvers import reverse_lazy
@@ -40,3 +42,11 @@
def bad_view(request, *args, **kwargs):
raise ValueError("I don't think I'm getting good value for this view")
+
+
+empty_view_partial = partial(empty_view, template_name="template.html")
+
+
+empty_view_wrapped = update_wrapper(
+ partial(empty_view, template_name="template.html"), empty_view,
+)
|