[英]django - regex for optional url parameters
我在django中有一个可以接受许多不同过滤器参数的视图,但它们都是可选的。 如果我有6个可选的过滤器,我是否真的必须为6的每个组合编写URL或者有没有办法定义url的哪些部分是可选的?
为了给你一个只有2个过滤器的例子,我可以拥有所有这些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>/
所有这些网址都指向相同的视图,唯一需要的参数是城市和州。 使用6个过滤器,这变得难以管理。
做我想做的最好的方法是什么?
一种方法是使正则表达式将所有给定的过滤器读取为单个字符串,然后将它们拆分为视图中的单个值。
我想出了以下网址:
(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
参数进行过滤,特别是如果用于过滤的网址不需要针对任何搜索引擎进行优化。 ..
尝试在urls.py中使用类似的东西:
url(r'^(?P<city>[^/]+)/(?P<state>[^/]+)/(radius/(?P<miles>[^/]+)/|company/(?P<company_name>[^/]+)/)*$', 'view')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.