django – regex для необязательных параметров URL

У меня есть представление в django, которое может принимать несколько различных параметров фильтра, но все они являются необязательными. Если у меня есть 6 дополнительных фильтров, действительно ли мне нужно писать URL-адреса для каждой комбинации из 6 или есть способ определить, какие части URL-адреса являются необязательными?

Чтобы дать вам пример с двумя фильтрами, я мог бы использовать все эти возможности URL:

/<city>/<state>/ /<city>/<state>/radius/<miles>/ /<city>/<state>/company/<company-name>/ /<city>/<state>/radius/<miles>/company/<company-name>/ /<city>/<state>/company/<company-name>/radius/<miles>/ 

Все эти URL указывают на одно и то же представление, и единственными требуемыми параметрами являются город и государство. С 6 фильтрами это становится неуправляемым.

Каков наилучший способ сделать то, что я хочу достичь?

  • Django: GET css возвращает 404?
  • Django: переменные параметры в URLconf
  • 4 Solutions collect form web for “django – regex для необязательных параметров URL”

    Один из методов заключался бы в том, чтобы регулярное выражение прочитало все указанные фильтры как одну строку, а затем разделило их на отдельные значения в представлении.

    Я придумал следующий URL:

     (r'^(?P<city>[^/]+)/(?P<state>[^/]+)(?P<filters>(?:/[^/]+/[^/]+)*)/?$', 'views.my_view'), 

    Соответствие требуемого города и штата легко. Часть filters немного сложнее. Внутренняя часть – (?:/[^/]+/[^/]+)* – соответствует фильтрам, указанным в форме /name/value . Однако квантификатор * (как и все кванторы регулярного выражения Python) возвращает только последнее найденное совпадение – так что если бы URL-адрес был /radius/80/company/mycompany/ only company/mycompany был бы сохранен. Вместо этого мы говорим, чтобы он не фиксировал отдельные значения (« ?: в начале») и помещал их в блок захвата, который будет хранить все значения фильтра как одну строку.

    Логика представления довольно проста. Обратите внимание, что регулярное выражение будет соответствовать парам фильтров – так что /company/mycompany/radius/ не будет соответствовать. Это означает, что мы можем с уверенностью предположить, что у нас есть пары значений. Представление, в котором я тестировал это, выглядит следующим образом:

     def my_view(request, city, state, filters): # Split into a list ['name', 'value', 'name', 'value']. Note we remove the # first character of the string as it will be a slash. split = filters[1:].split('/') # Map into a dictionary {'name': 'value', 'name': 'value'}. filters = dict(zip(split[::2], split[1::2])) # Get the values you want - the second parameter is the default if none was # given in the URL. Note all entries in the dictionary are strings at this # point, so you will have to convert to the appropriate types if desired. radius = filters.get('radius', None) company = filters.get('company', None) # Then use the values as desired in your view. context = { 'city': city, 'state': state, 'radius': radius, 'company': company, } return render_to_response('my_view.html', context) 

    Две вещи, чтобы отметить об этом. Во-первых, он позволяет просматривать неизвестные записи фильтров. Например, /fakefilter/somevalue действителен. Представленный выше код просмотра игнорирует их, но вы, вероятно, хотите сообщить об ошибке пользователю. Если это так, измените код, получая значения, чтобы

     radius = filters.pop('radius', None) company = filters.pop('company', None) 

    Любые записи, оставшиеся в словаре filters являются неизвестными значениями, о которых вы можете жаловаться.

    Во-вторых, если пользователь повторяет фильтр, последнее значение будет использоваться. Например, /radius/80/radius/50 задает радиус 50. Если вы хотите это обнаружить, вам нужно будет просмотреть список значений до его преобразования в словарь:

     given = set() for name in split[::2]: if name in given: # Repeated entry, complain to user or something. else: given.add(name) 

    Это абсолютно прецедент для параметров GET. Ваш urlconf должен быть просто /city/state/ , тогда различные фильтры идут в конце как переменные GET:

     /city/state/?radius=5&company=google 

    Теперь, на ваш взгляд, вы принимаете city и state как обычные параметры, но все остальное хранится в request.GET QueryDict.

    Вы также можете сделать только один URL-адрес (который проверяет только начало пути, это должно быть то же самое), указывающее на ваше представление, а затем проанализировать request.path в вашем представлении. С другой стороны, если у вас действительно много дополнительных параметров фильтра в различных комбинациях, лучшим решением является очень часто делать фильтрацию через GET -параметры, особенно если URL-адреса, используемые для фильтрации, не нуждаются в оптимизации для любой поисковой системы. ..

    Попробуйте использовать что-то подобное в urls.py:

     url(r'^(?P<city>[^/]+)/(?P<state>[^/]+)/(radius/(?P<miles>[^/]+)/|company/(?P<company_name>[^/]+)/)*$', 'view') 
    Python - лучший язык программирования в мире.