Django

Code

Changeset 4901

Show
Ignore:
Timestamp:
04/01/07 02:25:20 (2 years ago)
Author:
mtredinnick
Message:

Added the ability to name URL patterns. Helps with disambiguity reverse matches.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/conf/urls/defaults.py

    r4265 r4901  
    11from django.core.urlresolvers import RegexURLPattern, RegexURLResolver 
    22 
    3 __all__ = ['handler404', 'handler500', 'include', 'patterns'
     3__all__ = ['handler404', 'handler500', 'include', 'patterns', 'url'
    44 
    55handler404 = 'django.views.defaults.page_not_found' 
     
    88include = lambda urlconf_module: [urlconf_module] 
    99 
    10 def patterns(prefix, *tuples): 
     10def patterns(prefix, *args): 
    1111    pattern_list = [] 
    12     for t in tuples: 
    13         regex, view_or_include = t[:2] 
    14         default_kwargs = t[2:] 
    15         if type(view_or_include) == list: 
    16             pattern_list.append(RegexURLResolver(regex, view_or_include[0], *default_kwargs)) 
     12    for t in args: 
     13        if isinstance(t, (list, tuple)): 
     14            pattern_list.append(url(prefix=prefix, *t)) 
    1715        else: 
    18             pattern_list.append(RegexURLPattern(regex, prefix and (prefix + '.' + view_or_include) or view_or_include, *default_kwargs)
     16            pattern_list.append(t
    1917    return pattern_list 
     18 
     19def url(regex, view, kwargs=None, name=None, prefix=''): 
     20    if type(view) == list: 
     21        # For include(...) processing. 
     22        return RegexURLResolver(regex, view[0], kwargs) 
     23    else: 
     24        return RegexURLPattern(regex, prefix and (prefix + '.' + view) or view, kwargs, name) 
     25 
  • django/trunk/django/core/urlresolvers.py

    r4587 r4901  
    8989 
    9090class RegexURLPattern(object): 
    91     def __init__(self, regex, callback, default_args=None): 
     91    def __init__(self, regex, callback, default_args=None, name=None): 
    9292        # regex is a string representing a regular expression. 
    9393        # callback is either a string like 'foo.views.news.stories.story_detail' 
     
    101101            self._callback_str = callback 
    102102        self.default_args = default_args or {} 
     103        self.name = name 
    103104 
    104105    def resolve(self, path): 
     
    206207                lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name) 
    207208            except (ImportError, AttributeError): 
    208                 raise NoReverseMatch 
     209                if func_name != '': 
     210                    raise NoReverseMatch 
    209211        for pattern in self.urlconf_module.urlpatterns: 
    210212            if isinstance(pattern, RegexURLResolver): 
     
    213215                except NoReverseMatch: 
    214216                    continue 
    215             elif pattern.callback == lookup_view
     217            elif pattern.callback == lookup_view or pattern.name == lookup_view
    216218                try: 
    217219                    return pattern.reverse_helper(*args, **kwargs) 
  • django/trunk/docs/url_dispatch.txt

    r4804 r4901  
    186186The remaining arguments should be tuples in this format:: 
    187187 
    188     (regular expression, Python callback function [, optional dictionary]) 
    189  
    190 ...where ``optional dictionary`` is optional. (See 
    191 _`Passing extra options to view functions` below.) 
     188    (regular expression, Python callback function [, optional dictionary [, optional name]]) 
     189 
     190...where ``optional dictionary`` and ``optional name`` are optional. (See 
     191`Passing extra options to view functions`_ below.) 
     192 
     193url 
     194--- 
     195**New in development version** 
     196 
     197The ``url()`` function can be used instead of a tuple as an argument to 
     198``patterns()``. This is convenient if you wish to specify a name without the 
     199optional extra arguments dictionary. For example:: 
     200 
     201    urlpatterns = patterns('', 
     202        url(r'/index/$', index_view, name="main-view"), 
     203        ... 
     204    ) 
     205 
     206See `Naming URL patterns`_ for why then ``name`` parameter is useful. 
    192207 
    193208handler404 
     
    480495Note that if you use this technique -- passing objects rather than strings -- 
    481496the view prefix (as explained in "The view prefix" above) will have no effect. 
     497 
     498Naming URL patterns 
     499=================== 
     500 
     501**New in development version** 
     502 
     503It is fairly common to use the same view function in multiple URL patterns in 
     504your URLConf. This leads to problems when you come to do reverse URL matching, 
     505because the ``permalink()`` decorator and ``{% url %}`` template tag use the 
     506name of the view function to find a match. 
     507 
     508To solve this problem, you can give a name to each of your URL patterns in 
     509order to distinguish them from other patterns using the same views and 
     510parameters. You can then use this name wherever you would otherwise use the 
     511name of the view function. For example, if you URLConf contains:: 
     512 
     513    urlpatterns = patterns('', 
     514        url(r'/archive/(\d{4})/$', archive, name="full-archive"), 
     515        url(r'/archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"), 
     516    ) 
     517 
     518...you could refer to either the summary archive view in a template as:: 
     519 
     520    {% url arch-summary 1945 %} 
     521 
     522Even though both URL patterns refer to the ``archive`` view here, using the 
     523``name`` parameter to ``url()`` allows you to tell them apart in templates. 
     524 
     525The string used for the URL name can contain any characters you like. You are 
     526not restricted to valid Python names. 
     527 
     528.. note:: 
     529 
     530    Make sure that when you name your URLs, you use names that are unlikely to 
     531    clash with any other application's choice of names. If you call your URL 
     532    pattern *comment* and another application does the same thing, there is no 
     533    guarantee which URL will be inserted into your template when you use this 
     534    name. Putting a prefix on your URL names, perhaps derived from 
     535    the application name, will decrease the chances of collision. Something 
     536    like *myapp-comment* is recommended over simply *comment*. 
     537 
  • django/trunk/tests/regressiontests/templates/tests.py

    r4885 r4901  
    693693            'url02' : ('{% url regressiontests.templates.views.client_action client.id,action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'), 
    694694            'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'), 
     695            'url04' : ('{% url named-client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'), 
    695696 
    696697            # Failures 
    697             'url04' : ('{% url %}', {}, template.TemplateSyntaxError), 
    698             'url05' : ('{% url no_such_view %}', {}, ''), 
    699             'url06' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''), 
     698            'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError), 
     699            'url-fail02' : ('{% url no_such_view %}', {}, ''), 
     700            'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''), 
    700701        } 
    701702 
  • django/trunk/tests/regressiontests/templates/urls.py

    r4494 r4901  
    88    (r'^client/(\d+)/$', views.client), 
    99    (r'^client/(\d+)/(?P<action>[^/]+)/$', views.client_action), 
     10    url(r'^named-client/(\d+)/$', views.client, name="named-client"), 
    1011)