Skip to content

Instantly share code, notes, and snippets.

@justinvh
Last active August 29, 2015 13:57
Show Gist options
  • Save justinvh/9350254 to your computer and use it in GitHub Desktop.
Save justinvh/9350254 to your computer and use it in GitHub Desktop.
Automatic JavaScript Django URL Resolver
var {{ namespace }} = {};
{{ namespace }}.urls = {{ urls }};
{{ namespace }}.resolve = function (name, kwargs) {
var path = {{ namespace }}.urls[name];
if (!path) {
throw('URL not found for view: ' + name);
}
var original_path = path;
for (var key in kwargs) {
if (!kwargs.hasOwnProperty(key)) {
continue;
}
if (!path.match('<' + key +'>')) {
throw(key + ' does not exist in ' + original_path);
}
path = path.replace('<' + key +'>', kwargs[key]);
}
var re = new RegExp('<[a-zA-Z0-9-_]{1,}>', 'g');
var missing_args = path.match(re);
if (missing_args) {
throw('Missing arguments ('
+ missing_args.join(", ") + ') for url ' + _path);
}
return path;
};
{{ namespace }}.getJSON = function (name, kwargs, params, callback) {
if (typeof(params) === "function") {
callback = params;
params = {};
}
return $.getJSON({{ namespace }}.resolve(name, kwargs), params, callback);
};
import sys
import re
import json
from django.shortcuts import render
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
from django.utils.datastructures import SortedDict
from django.conf import settings
from django.utils.safestring import mark_safe
# Pattern for recognizing unnamed url parameters
RE_KWARG = re.compile(r"(\(\?P\<(.*?)\>.*?\))")
# Pattern for recongnizing named parameters in urls
RE_ARG = re.compile(r"(\(.*?\))")
def handle_url_module(js_patterns, module_name, prefix="", namespace=None):
"""Processes a specific URL module.
Each URL module will be resolved and then the regex will be mapped
for a JavaScript expression.
"""
def parse_regex_url_resolver(prefix, pattern, js_patterns, namespace=None):
"""Parse a specific URL resolver from a URL module.
This will nest namespaces appropriately.
"""
kwargs = {}
full_namespace = pattern.namespace
if pattern.namespace:
if namespace:
full_namespace = u'{}:{}'.format(namespace, pattern.namespace)
kwargs['namespace'] = full_namespace
namespace = pattern.urlconf_name or namespace
prefix = '{}{}'.format(prefix, pattern.regex.pattern)
handle_url_module(js_patterns, namespace, prefix=prefix, **kwargs)
def parse_regex_url_pattern(prefix, namespace, pattern, js_patterns):
"""Parse a specific URL regex instance.
This method ultimately creates the pattern that will be used
by JavaScript to resolve the URLs.
"""
full_url = prefix + pattern.regex.pattern
for char in ('^', '$'):
full_url = full_url.replace(char, '')
kwarg_matches = RE_KWARG.findall(full_url)
if kwarg_matches:
for e in kwarg_matches:
full_url = full_url.replace(e[0], '<{}>'.format(e[1]))
args_matches = RE_ARG.findall(full_url)
if args_matches:
for el in args_matches:
full_url = full_url.replace(el, '<>')
key = pattern.name
if namespace:
key = '{}:{}'.format(namespace, pattern.name)
js_patterns[key] = '/{}'.format(full_url)
if isinstance(module_name, str):
__import__(module_name)
root_urls = sys.modules[module_name]
patterns = root_urls.urlpatterns
else:
root_urls = module_name
patterns = root_urls
if not hasattr(patterns, "__iter__"):
patterns = patterns.urlpatterns
for pattern in patterns:
if issubclass(pattern.__class__, RegexURLPattern):
if pattern.name:
parse_regex_url_pattern(prefix, namespace,
pattern, js_patterns)
elif issubclass(pattern.__class__, RegexURLResolver):
if pattern.urlconf_name or pattern.namespace:
parse_regex_url_resolver(prefix, pattern,
js_patterns, namespace)
def urls(request):
js_patterns = SortedDict()
handle_url_module(js_patterns, settings.ROOT_URLCONF)
patterns = mark_safe(json.dumps(js_patterns, indent=4))
context = {'urls': patterns, 'namespace': u'smashmap'}
template_name = 'smashmap/urls.js'
content_type = 'text/javascript'
return render(request, template_name, context, content_type=content_type)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment