Django: Arbitrary number of unnamed urls.py parameters
Asked Answered
W

5

22

I have a Django model with a large number of fields and 20000+ table rows. To facilitate human readable URLs and the ability to break down the large list into arbitrary sublists, I would like to have a URL that looks like this:

/browse/<name1>/<value1>/<name2>/<value2>/ .... etc ....

where 'name' maps to a model attribute and 'value' is the search criteria for that attribute. Each "name" will be treated like a category to return subsets of the model instances where the categories match.

Now, this could be handled with GET parameters, but I prefer more readable URLs for both the user's sake and the search engines. These URLs subsets will be embedded on each page that displays this model, so it seems worth the effort to make pretty URLs.

Ideally each name/value pair will be passed to the view function as a parameter named name1, name2, etc. However, I don't believe it's possible to defined named patterns via a regex's matched text. Am I wrong there?

So, it seems I need to do something like this:

urlpatterns = patterns('',
    url(r'^browse/(?:([\w]+)/([\w]+)/)+$', 'app.views.view', name="model_browse"),
)

It seems this should match any sets of two name/value pairs. While it matches it successfully, it only passes the last name/value pair as parameters to the view function. My guess is that each match is overwriting the previous match. Under the guess that the containing (?:...)+ is causing it, I tried a simple repeating pattern instead:

urlpatterns = patterns('',
    url(r'^browse/([\w]+/)+$', 'app.views.view', name="model_browse"),
)

... and got the same problem, but this time *args only includes the last matched pattern.

Is this a limitation of Django's url dispatcher, and/or Python's regex support? It seems either of these methods should work. Is there a way to achieve this without hardcoding each possible model attribute in the URL as an optional (.*) pattern?

Wellappointed answered 30/10, 2008 at 2:18 Comment(2)
I think that implement "GET query like" key-value params using url itself is a bit ugly and not "true".Stiles
@alex - besides that the url isn't readable, search engines likely won't index all your content if you have more than a couple get parameters (if that).Wellappointed
E
15

A possibility that you might consider is matching the entire string of possible values within the url pattern portion and pull out the specific pieces within your view. As an example:

urlpatterns = patterns('',
    url(r'^browse/(?P<match>.+)/$', 'app.views.view', name='model_browse'),
)

def view(request, match):
    pieces = match.split('/')
    # even indexed pieces are the names, odd are values
    ...

No promises about the regexp I used, but I think you understand what I mean.

(Edited to try and fix the regexp.)

Empennage answered 30/10, 2008 at 7:52 Comment(3)
Thanks, I agree this is probably the easiest way to handle the problem.Wellappointed
Just to put some text on here for others in my situation, this is the only solution I have found for parsing an arbitrary number of matrix elements in a matrix URI. Match all matrix elements together and then parse in the view.Polytechnic
same here, and it's 2016Crescin
T
3

I agree with Adam, but I think the pattern in urls.py should be:

... r'^browse/(?P<match>.+)/$' ...

The '\w' will only match 'word' characters, but the '.' will match anything.

Teledu answered 30/10, 2008 at 18:32 Comment(1)
I'm terrible at regular expressions and just guessed, heh.Empennage
E
1

I've an alternative solution, which isn't quite different from the previous but it's more refined:

url(r'^my_app/(((list\/)((\w{1,})\/(\w{1,})\/(\w{1,3})\/){1,10})+)$'

I've used unnamed url parameters and a repetitive regexp. Not to get the "is not a valid regular expression: multiple repeat" i place a word at the beginning of the list.

I'm still working at the view receiving the list. But i think ill' go through the args or kwargs.. Cannot still say it exactly.

My 2 cents

Economist answered 23/2, 2016 at 10:37 Comment(0)
S
0

Same answer came to me while reading the question.

I believe model_browse view is the best way to sort the query parameters and use it as a generic router.

Scapula answered 31/10, 2008 at 23:31 Comment(0)
N
0

I think the answer of Adam is more generic than my solution, but if you like to use a fixed number of arguments in the url, you could also do something like this:

The following example shows how to get all sales of a day for a location by entering the name of the store and the year, month and day.

urls.py:

urlpatterns = patterns('',
    url(r'^baseurl/location/(?P<store>.+)/sales/(?P<year>[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9])-(?P<day>[0-9][0-9])/$', views.DailySalesAtLocationListAPIView.as_view(), name='daily-sales-at-location'),
)

Alternativly, you could also use the id of the store by changing (?P<store>.+) to (?P<store>[0-9]+). Note that location and sales are no keywords, they just improve readability of the url.

views.py

class DailySalesAtLocationListAPIView(generics.ListAPIView):
    def get(self, request, store, year, month, day):
        # here you can start using the values from the url
        print store
        print year
        print month
        print date

        # now start filtering your model

Hope it helps anybody!

Best regards,

Michael

Neuberger answered 15/10, 2013 at 10:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.