3

How to pass multi optional URL parameters?

For example I want pass 2 params: my_color and my_year, but they are optional, so may be none of them will be passed, may be both, or may be only one.

Currently in urls.py I have :

urlpatterns = [
    re_path(r'^products/(?P<my_color>.*)/(?P<my_year>.*)$', some_view),
]

This obviously is not correct and works only if both of them are passed.

What would be correct solution?

P.S. I found answers when only one optional parameter needs to be pass, but not figured out how to do same for few parameters. Also it seems "multiple-routes option" is not solution in this case (?)

Oto Shavadze
  • 40,603
  • 55
  • 152
  • 236

1 Answers1

4

If myyear is a sequence of digits, and mycolor is a equence of non-digits, you can use

urlpatterns = [
    re_path(r'^products/((?P<my_color>\D+)/)?(?P<my_year>\d+)$', some_view),
]

this will pass an empty string for the corresponding elements if the my_color or my_year are not present. You thus can write a view that looks like:

def some_view(request, my_color, my_year):
    if my_color:
        # …
    if my_year:
        # …

If both have the same sequence of characters, this is not possible, since how would you interpret products/bla? Is bla the color, or the year?

That being said, I think you make it too complicated. You can define four patterns, for example:

urlpatterns = [
    path(r'^products/', some_view),
    path(r'^products/<int:year>/'),
    path(r'^products/<str:color>/'),
    path(r'^products/<str:color>/<int:year>/', some_view),
]

Here you thus define four views for the same view. The view can then define optional parameter:

def some_view(request, color=None, year=None):
    # …
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • "If both have the same sequence of characters, this is not possible, since how would you interpret products/bla? Is bla the color, or the year?" this is exactly what I don't get. example is about 2 parameters, but what if we need to pass 10 optional params ? – Oto Shavadze Oct 05 '20 at 00:00
  • @OtoShavadze: but your parameters are *optional*, imagine that you can both capture a `color` and a size, how will you interpret `/large`? Is `large` a `color` or a `size`? Semantically of course it is a size, but it will be hard to write a regex that only captures colors. The optional part results in ambiguity. – Willem Van Onsem Oct 05 '20 at 00:03
  • Yes, you are correct, but how to solve cases like this then? May be just pass params using standart way `/?my_color=a&my_year=b` is only one way ? – Oto Shavadze Oct 05 '20 at 00:05
  • @OtoShavadze: I think for a large amount of optional parameters, that is the preferred way, since then it is clear what the parameter is. Furthermore it is more convenient, since Django will already wrap this in a dictionary-like object. – Willem Van Onsem Oct 05 '20 at 00:06