Search code examples
pythonregexdjangogroupingurlconf

Django: match one or more from a set of keyworded regular expressions in an urlconf


I have a Django view that takes three optional keyworded arguments. I want to handle the regular expression for matching possible urls to this view in one line. I want to structure the urls nicely.

An example: My possible parameters are start which is an int, serial which is a string of length 13, and end which is another int.

An url might look like:

/main/s20130509/e20130510/ABC1234567890
or
/main/s20130509/e20130510/
or 
/main/ABC1234567890

Where the e and s prefixed components are end and start respectively, and ABC1234567890 is serial.

I want to pull these end, start, serial values and pass them to the view as values start=s20130509, etc...

Right now I am doing this by exhaustively listing the permutations on separate lines, and it seems like there must be a better way.

I'm trying to do something like:

url(r'^base_url/(?P<serial>[^/]{13}|(?P<end>e\d{8})|(?P<start>s\d{8})/*$', view_method),

Basically, the logic of what I want to do is clear to me; I want to pull all instances of any of the three matches and pass them as keyworded params, but I can't find a resource to figure out the ReGex syntax to fit this.

Any thoughts? I'm happy to do pretty much whatever gets the job done elegantly.

Thanks for your time,

Tim


Solution

  • What you're wanting is:

    url(r'^base_url/(?P<serial>[^/]{13}/$', view_method),
    

    with the addition of optional groups for the end and start kwargs, so:

    # Optional, non-capturing group surrounding the named group for each (so you don't have to capture the slashes or the "e" or "s"
    (?:e(?P<end>\d{8})/)
    

    Then, allow up to 2 of those, in either order:

    ((?:s(?P<start>\d{8})/)|(?:e(?P<end>\d{8})/)){0,2}
    

    The result is:

    url(r'^base_url/((?:s(?P<start>\d{8})/)|(?:e(?P<end>\d{8})/)){0,2}(?P<serial>[^/]{13})/$', view_method),
    

    Disclaimer, I wrote this in this box, so it'll take me a moment to test it and update the answer (if it's wrong).

    Update:

    Indeed, it worked :) I matched the following:

    http://127.0.0.1:8080/base_url/e77777777/s88888888/1234567890123/
    http://127.0.0.1:8080/base_url/s88888888/e77777777/1234567890123/
    http://127.0.0.1:8080/base_url/s88888888/1234567890123/
    http://127.0.0.1:8080/base_url/e77777777/1234567890123/
    http://127.0.0.1:8080/base_url/1234567890123/
    

    The kwargs looked like this (raised in an exception from the get method of a sub-class of View when requested with all three segments - the end and/or start were None when left out):

    {'start': u'88888888', 'serial': u'1234567890123', 'end': u'77777777'}