Author: adrian
Date: 2006-08-11 02:01:29 -0500 (Fri, 11 Aug 2006)
New Revision: 3554

Modified:
   django/trunk/django/core/urlresolvers.py
   django/trunk/docs/url_dispatch.txt
Log:
Improved urlresolvers so that URLconfs can be passed objects instead of strings

Modified: django/trunk/django/core/urlresolvers.py
===================================================================
--- django/trunk/django/core/urlresolvers.py    2006-08-11 05:31:08 UTC (rev 
3553)
+++ django/trunk/django/core/urlresolvers.py    2006-08-11 07:01:29 UTC (rev 
3554)
@@ -86,10 +86,15 @@
 class RegexURLPattern(object):
     def __init__(self, regex, callback, default_args=None):
         # regex is a string representing a regular expression.
-        # callback is something like 'foo.views.news.stories.story_detail',
-        # which represents the path to a module and a view function name.
+        # callback is either a string like 
'foo.views.news.stories.story_detail'
+        # which represents the path to a module and a view function name, or a
+        # callable object (view).
         self.regex = re.compile(regex)
-        self.callback = callback
+        if callable(callback):
+            self._callback = callback
+        else:
+            self._callback = None
+            self._callback_str = callback
         self.default_args = default_args or {}
 
     def resolve(self, path):
@@ -106,24 +111,29 @@
             # In both cases, pass any extra_kwargs as **kwargs.
             kwargs.update(self.default_args)
 
-            try: # Lazily load self.func.
-                return self.func, args, kwargs
-            except AttributeError:
-                self.func = self.get_callback()
-            return self.func, args, kwargs
+            return self.callback, args, kwargs
 
-    def get_callback(self):
-        mod_name, func_name = get_mod_func(self.callback)
+    def _get_callback(self):
+        if self._callback is not None:
+            return self._callback
+        mod_name, func_name = get_mod_func(self._callback_str)
         try:
-            return getattr(__import__(mod_name, '', '', ['']), func_name)
+            self._callback = getattr(__import__(mod_name, '', '', ['']), 
func_name)
         except ImportError, e:
             raise ViewDoesNotExist, "Could not import %s. Error was: %s" % 
(mod_name, str(e))
         except AttributeError, e:
             raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % 
(func_name, mod_name, str(e))
+        return self._callback
+    callback = property(_get_callback)
 
     def reverse(self, viewname, *args, **kwargs):
-        if viewname != self.callback:
+        mod_name, func_name = get_mod_func(viewname)
+        try:
+            lookup_view = getattr(__import__(mod_name, '', '', ['']), 
func_name)
+        except (ImportError, AttributeError):
             raise NoReverseMatch
+        if lookup_view != self.callback:
+            raise NoReverseMatch
         return self.reverse_helper(*args, **kwargs)
 
     def reverse_helper(self, *args, **kwargs):
@@ -185,22 +195,28 @@
     def resolve500(self):
         return self._resolve_special('500')
 
-    def reverse(self, viewname, *args, **kwargs):
+    def reverse(self, lookup_view, *args, **kwargs):
+        if not callable(lookup_view):
+            mod_name, func_name = get_mod_func(lookup_view)
+            try:
+                lookup_view = getattr(__import__(mod_name, '', '', ['']), 
func_name)
+            except (ImportError, AttributeError):
+                raise NoReverseMatch
         for pattern in self.urlconf_module.urlpatterns:
             if isinstance(pattern, RegexURLResolver):
                 try:
-                    return pattern.reverse_helper(viewname, *args, **kwargs)
+                    return pattern.reverse_helper(lookup_view, *args, **kwargs)
                 except NoReverseMatch:
                     continue
-            elif pattern.callback == viewname:
+            elif pattern.callback == lookup_view:
                 try:
                     return pattern.reverse_helper(*args, **kwargs)
                 except NoReverseMatch:
                     continue
         raise NoReverseMatch
 
-    def reverse_helper(self, viewname, *args, **kwargs):
-        sub_match = self.reverse(viewname, *args, **kwargs)
+    def reverse_helper(self, lookup_view, *args, **kwargs):
+        sub_match = self.reverse(lookup_view, *args, **kwargs)
         result = reverse_helper(self.regex, *args, **kwargs)
         return result + sub_match
 

Modified: django/trunk/docs/url_dispatch.txt
===================================================================
--- django/trunk/docs/url_dispatch.txt  2006-08-11 05:31:08 UTC (rev 3553)
+++ django/trunk/docs/url_dispatch.txt  2006-08-11 07:01:29 UTC (rev 3554)
@@ -431,3 +431,48 @@
 URLconf, regardless of whether the line's view actually accepts those options
 as valid. For this reason, this technique is only useful if you're certain that
 every view in the the included URLconf accepts the extra options you're 
passing.
+
+Passing callable objects instead of strings
+===========================================
+
+**New in the Django development version.**
+
+Some developers find it more natural to pass the actual Python function object
+rather than a string containing the path to its module. This alternative is
+supported -- you can pass any callable object as the view.
+
+For example, given this URLconf in "string" notation::
+
+    urlpatterns = patterns('',
+        (r'^archive/$', 'mysite.views.archive'),
+        (r'^about/$', 'mysite.views.about'),
+        (r'^contact/$', 'mysite.views.contact'),
+    )
+
+You can accomplish the same thing by passing objects rather than strings. Just
+be sure to import the objects::
+
+    from mysite.views import archive, about, contact
+
+    urlpatterns = patterns('',
+        (r'^archive/$', archive),
+        (r'^about/$', about),
+        (r'^contact/$', contact),
+    )
+
+The following example is functionally identical. It's just a bit more compact
+because it imports the module that contains the views, rather than importing
+each view individually::
+
+    from mysite import views
+
+    urlpatterns = patterns('',
+        (r'^archive/$', views.archive),
+        (r'^about/$', views.about),
+        (r'^contact/$', views.contact),
+    )
+
+The style you use is up to you.
+
+Note that if you use this technique -- passing objects rather than strings --
+the view prefix (as explained in "The view prefix" above) will have no effect.


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates
-~----------~----~----~----~------~----~------~--~---

Reply via email to