Opened 9 years ago

Last modified 5 years ago

#25409 assigned New feature

Allow url and groups of urls to be easily tagged and selected — at Version 1

Reported by: Atul Bhouraskar Owned by: Atul Bhouraskar
Component: Core (URLs) Version: dev
Severity: Normal Keywords:
Cc: barfieldsamueliii10@…, Atul Bhouraskar Triage Stage: Someday/Maybe
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Atul Bhouraskar)

The Problem

Often (usually in middleware) processing has to be applied to a certain URLs only eg CORS.

The usual way to specify this would be to create an additional set of regex patterns identifying these urls - eg.

CORS_URLS_REGEX = r'^/api/.*$'

The middleware then typically matches the incoming request URL to the regex and determines whether it is to be selected for processing.

This approach has several limitations including:

  • It violates DRY as the regexes in the settings have to be synced with the actual URL patterns
  • Matching multiple patterns may require the app writer to essentially reinvent URL patterns - poorly.

The Proposal

Add an optional tags keyword argument to django.conf.urls.url allowing a URL to be optionally tagged with one or more tags which can then be retrieved via HttpRequest.resolver_match.tags in the middleware / view etc.

urlpatterns = [
    url(r'^$', views.home, name='home'),
    url(r'^articles/$', views.show_articles, name='show-articles', tags=['require_GET']),
    url(r'^private/$', include(private_patterns), tags=['login_required']),
    url(r'^api/', include(api_patterns), tags=[
        'cors_allowed', 'nologin_forbidden', 'ajax_required'
    ]),
]

In the example above, the home url has no tags, the show-articles url is tagged require_GET, the urls under private/ are all tagged login_required while the the urls under api/ have multiple tags.

This allows app middleware to selectively process urls very easily:

class LoginRequiredMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if 'login_required' in request.resolver_match.tags and \
                not request.user.is_authenticated():
            return redirect('login')

class RequireGETMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if 'require_GET' in request.resolver_match.tags and request.method != 'GET':
            return HttpResponseNotAllowed(['GET'])

class AjaxRequiredMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if 'ajax_required' in request.resolver_match.tags and not request.is_ajax():
            return HttpResponseForbidden()

class CorsMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if 'cors_allowed' in request.resolver_match.tags:
            # continue CORS processing

I am attaching a patch that implements this tagging feature to urlpatterns. It has tests (docs to be added). The change is fully backwards compatible as specifying tags is completely optional, all existing tests pass with the patch applied to master.

I'm working on my branch at https://github.com/atul-bhouraskar/django/tree/ticket_25409

Comments welcome!

Change History (2)

by Atul Bhouraskar, 9 years ago

Attachment: urltags.patch added

Patch implementing url tagging.

comment:1 by Atul Bhouraskar, 9 years ago

Description: modified (diff)
Owner: changed from nobody to Atul Bhouraskar
Status: newassigned
Note: See TracTickets for help on using tickets.
Back to Top