diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index ce064c9926..a8f52a6c8e 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -41,7 +41,12 @@ class ResolverMatch(object): else: self.namespaces = [] if not url_name: - url_name = '.'.join([ func.__module__, func.__name__ ]) + if not hasattr(func, '__name__'): + # An instance of a callable class + url_name = '.'.join([func.__class__.__module__, func.__class__.__name__]) + else: + # A function + url_name = '.'.join([func.__module__, func.__name__]) self.url_name = url_name def namespace(self): diff --git a/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py index 5dc302c862..16887e2a9b 100644 --- a/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py +++ b/tests/regressiontests/urlpatterns_reverse/included_namespace_urls.py @@ -1,5 +1,6 @@ from django.conf.urls.defaults import * from namespace_urls import URLObject +from views import view_class_instance testobj3 = URLObject('testapp', 'test-ns3') @@ -10,6 +11,8 @@ urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', url(r'^mixed_args/(\d+)/(?P\d+)/$', 'empty_view', name='inc-mixed-args'), url(r'^no_kwargs/(\d+)/(\d+)/$', 'empty_view', name='inc-no-kwargs'), + url(r'^view_class/(?P\d+)/(?P\d+)/$', view_class_instance, name='inc-view-class'), + (r'^test3/', include(testobj3.urls)), (r'^ns-included3/', include('regressiontests.urlpatterns_reverse.included_urls', namespace='inc-ns3')), (r'^ns-included4/', include('regressiontests.urlpatterns_reverse.namespace_urls', namespace='inc-ns4')), diff --git a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py index e7991585f0..3d34049932 100644 --- a/tests/regressiontests/urlpatterns_reverse/namespace_urls.py +++ b/tests/regressiontests/urlpatterns_reverse/namespace_urls.py @@ -1,4 +1,5 @@ from django.conf.urls.defaults import * +from views import view_class_instance class URLObject(object): def __init__(self, app_name, namespace): @@ -26,6 +27,11 @@ urlpatterns = patterns('regressiontests.urlpatterns_reverse.views', url(r'^mixed_args/(\d+)/(?P\d+)/$', 'empty_view', name='mixed-args'), url(r'^no_kwargs/(\d+)/(\d+)/$', 'empty_view', name='no-kwargs'), + url(r'^view_class/(?P\d+)/(?P\d+)/$', view_class_instance, name='view-class'), + + (r'^unnamed/normal/(?P\d+)/(?P\d+)/$', 'empty_view'), + (r'^unnamed/view_class/(?P\d+)/(?P\d+)/$', view_class_instance), + (r'^test1/', include(testobj1.urls)), (r'^test2/', include(testobj2.urls)), (r'^default/', include(default_testobj.urls)), diff --git a/tests/regressiontests/urlpatterns_reverse/tests.py b/tests/regressiontests/urlpatterns_reverse/tests.py index 7bf96d17c6..1a50fd6413 100644 --- a/tests/regressiontests/urlpatterns_reverse/tests.py +++ b/tests/regressiontests/urlpatterns_reverse/tests.py @@ -32,12 +32,18 @@ resolve_test_data = ( # These entries are in the format: (path, url_name, app_name, namespace, view_func, args, kwargs) # Simple case ('/normal/42/37/', 'normal-view', None, '', views.empty_view, tuple(), {'arg1': '42', 'arg2': '37'}), + ('/view_class/42/37/', 'view-class', None, '', views.view_class_instance, tuple(), {'arg1': '42', 'arg2': '37'}), ('/included/normal/42/37/', 'inc-normal-view', None, '', views.empty_view, tuple(), {'arg1': '42', 'arg2': '37'}), + ('/included/view_class/42/37/', 'inc-view-class', None, '', views.view_class_instance, tuple(), {'arg1': '42', 'arg2': '37'}), # Unnamed args are dropped if you have *any* kwargs in a pattern ('/mixed_args/42/37/', 'mixed-args', None, '', views.empty_view, tuple(), {'arg2': '37'}), ('/included/mixed_args/42/37/', 'inc-mixed-args', None, '', views.empty_view, tuple(), {'arg2': '37'}), + # Unnamed views will be resolved to the function/class name + ('/unnamed/normal/42/37/', 'regressiontests.urlpatterns_reverse.views.empty_view', None, '', views.empty_view, tuple(), {'arg1': '42', 'arg2': '37'}), + ('/unnamed/view_class/42/37/', 'regressiontests.urlpatterns_reverse.views.ViewClass', None, '', views.view_class_instance, tuple(), {'arg1': '42', 'arg2': '37'}), + # If you have no kwargs, you get an args list. ('/no_kwargs/42/37/', 'no-kwargs', None, '', views.empty_view, ('42','37'), {}), ('/included/no_kwargs/42/37/', 'inc-no-kwargs', None, '', views.empty_view, ('42','37'), {}), diff --git a/tests/regressiontests/urlpatterns_reverse/views.py b/tests/regressiontests/urlpatterns_reverse/views.py index 99c00bde70..27dca3d0e2 100644 --- a/tests/regressiontests/urlpatterns_reverse/views.py +++ b/tests/regressiontests/urlpatterns_reverse/views.py @@ -6,3 +6,9 @@ def kwargs_view(request, arg1=1, arg2=2): def absolute_kwargs_view(request, arg1=1, arg2=2): pass + +class ViewClass(object): + def __call__(self, request, *args, **kwargs): + pass + +view_class_instance = ViewClass()