[First timer participating in the Django dev process, so apologies if
I have missed some protocol etc.]

First up, this is not about adding an alternate URL
resolution/reversal method to the core; I've noticed a fair bit of
resistance to that.

PROBLEM:
I want to make my website available via an API with URLs like this -
http://example.com/newitems/ => returns HTML
http://example.com/newitems.xml => returns XML
http://example.com/newitems.json => returns JSON.

To represent this in urls.py, I have to either:
a) write a separate url entry for each one
b) write 2 url entries, one for newitems/ and another for
newitems\.(?P<format>\w+). This is the better option, but still
annoying. Plus it forces my view to validate whether or not the format
value is acceptable (e.g. is either xml or json).

I have to do this for every URL I wish to make available via an API,
bloating out my urls.py file. (I'm aware I can use the HTTP-ACCEPT
header instead, but there is a need to be able to force the response
format in the URL for certain uses.)

MY DESIRED SOLUTION:
Subclass RegexURLPattern, and override the resolve method so that it
will replace a placeholder, e.g. (?#format), with the appropriate
regexps (/|\.xml|\.json). Effectively it will perform something
similar to this regexp instead -
^newitems(/|(?P<format>(\.xml|\.json))) where the list of accepted
formats will be defined in settings. This subclass will be returned
using an alternate url(...) call, e.g. murl(...).

So my urls.py will look like -
urlpatterns = patterns('project.app.views',
    murl(r'^/(?P<model_id>\d+)(?#format)$', AppView.as_view(),
name='app_view1'),
)

(For completeness, the view is a CBV, and uses the format arg to
determine which template to render, and using what MIME type to
respond.)

This is a proven way of extending the URL system, as demonstrated by
the various projects out there for alternative URL specification
syntaxes, e.g. django-easyurls.

ROADBLOCK:
The issue with this solution is that while resolving will work fine,
reversing will not. The list of possible URLs for a particular view is
determined by _populate in RegexURLResolver, and is based on the
regexp pattern alone. Django doesn't support | in regexps
(understandably), and there is no way to supplant this with additional
regexps or possibilities at the moment, even though the infrastructure
is there during reversal.

RESOLUTION - PHASE 1:
Because of the friction and work required to fully revamp the URL
resolution system, this phase is a short, simple fix that will suffice
for most cases where people want to extend the URL resolution system.

Refactor out line 218 (in trunk) in django/core/urlresolvers.py:

bits = normalize(p_pattern)

... into a separate method in RegexURLPattern:

def get_possibilities(self):
    return normalize(self.regex.pattern)

... and replace line 218 in django/core/urlresolvers.py with:

bits = pattern.get_possibilities()

That's it. I'll create a patch for this later if the consensus is
positive. The above change allows subclassed RegexURLPattern classes
to alter what is returned as possible URLs from that pattern. I'm
hoping this simple change can be made in Django 1.3.

Of course, the possibilities returned still have to be regexps, which
leads to phase 2...

RESOLUTION - PHASE 2:
The ultimate goal should be a URL resolution system that allows
alternate URL spec syntaxes to be first-class citizens, allowing
regexp based URL specs and say, URI Template specs to exist
side-by-side.

My plan would be to create an abstract base class for all URLPatterns,
which RegexURLPattern will extend. The existing behaviour will mostly
stay, except the get_possibilities from phase 1 will be deprecated in
favour of a new reverse method. The reverse method will be called by
the new universal URLResolver class for matches when reversing URLs,
and if a match exists, that will be returned. During _populate(), the
new universal URLResolver class will group URLPattern objects by view
callback and name, instead of the output of
get_possibilities/normalize.

This approach requires no changes to existing urls.py; in fact, from a
dev perspective, they would only notice the difference if they choose
to use alternate URL spec syntaxes. The existing regexp system will
work as it has always worked. And it makes sense that the URLPattern
object is responsible for resolving and reversing itself, and not the
resolver.

Until this phase is reached, the API should be considered private so
devs are on notice that things will change and may break existing
custom URL resolution code.

Again, I'm happy to have a crack at making this work if the consensus
is positive.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to