django - 可选 url 参数的正则表达式
我在 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>/
所有这些 url 都指向同一个视图,唯一需要的参数是城市和州。如果有 6 个过滤器,这将变得难以管理。
实现我想要实现的目标的最佳方法是什么?
I have a view in django that can accept a number of different filter parameters, but they are all optional. If I have 6 optional filters, do I really have to write urls for every combination of the 6 or is there a way to define what parts of the url are optional?
To give you an example with just 2 filters, I could have all of these url possibilities:
/<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>/
All of these url's are pointing to the same view and the only required params are city and state. With 6 filters, this becomes unmanageable.
What's the best way to go about doing what I want to achieve?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一种方法是让正则表达式将所有给定的过滤器作为单个字符串读取,然后将它们拆分为视图中的各个值。
我想出了以下 URL:
匹配所需的城市和州很容易。
filters
部分有点复杂。内部部分 -(?:/[^/]+/[^/]+)*
- 匹配以/name/value
形式给出的过滤器。但是,*
量词(与所有 Python 正则表达式量词一样)仅返回找到的最后一个匹配项 - 因此,如果 url 为/radius/80/company/mycompany/
则仅 < code>company/mycompany 将被存储。相反,我们告诉它不要捕获单个值(开头的?:
),并将其放入捕获块中,该捕获块会将所有过滤器值存储为单个字符串。视图逻辑相当简单。请注意,正则表达式仅匹配过滤器对 - 因此
/company/mycompany/radius/
将不会匹配。这意味着我们可以安全地假设我们有成对的值。我对此进行测试的视图如下:关于此需要注意的两件事。首先,它允许未知的过滤器条目进入您的视图。例如,
/fakefilter/somevalue
是有效的。上面的视图代码忽略了这些,但您可能想向用户报告错误。如果是这样,请将获取值的代码更改为filters
字典中剩余的任何条目都是您可以抱怨的未知值。其次,如果用户重复过滤,则将使用最后一个值。例如,
/radius/80/radius/50
会将半径设置为 50。如果您想检测到这一点,则需要在将其转换为字典之前扫描值列表:One method would be to make the regular expression read all the given filters as a single string, and then split them up into individual values in the view.
I came up with the following URL:
Matching the required city and state is easy. The
filters
part is a bit more complicated. The inner part -(?:/[^/]+/[^/]+)*
- matches filters given in the form/name/value
. However, the*
quantifier (like all Python regular expression quantifiers) only returns the last match found - so if the url was/radius/80/company/mycompany/
onlycompany/mycompany
would be stored. Instead, we tell it not to capture the individual values (the?:
at the start), and put it inside a capturing block which will store all filter values as a single string.The view logic is fairly straightforward. Note that the regular expression will only match pairs of filters - so
/company/mycompany/radius/
will not be matched. This means we can safely assume we have pairs of values. The view I tested this with is as follows:Two things to note about this. First, it allows unknown filter entries into your view. For example,
/fakefilter/somevalue
is valid. The view code above ignores these, but you probably want to report an error to the user. If so, alter the code getting the values toAny entries remaining in the
filters
dictionary are unknown values about which you can complain.Second, if the user repeats a filter, the last value will be used. For example,
/radius/80/radius/50
will set the radius to 50. If you want to detect this, you will need to scan the list of values before it is converted to a dictionary:这绝对是 GET 参数的用例。您的 urlconf 应该只是
/city/state/
,然后各种过滤器作为 GET 变量放在最后:现在,在您看来,您接受
city
和state
作为普通参数,但其他所有内容都存储在request.GET
QueryDict 中。This is absolutely the use-case for GET parameters. Your urlconf should just be
/city/state/
, then the various filters go on the end as GET variables:Now, in your view, you accept
city
andstate
as normal parameters, but everything else is stored in therequest.GET
QueryDict.您还可以只创建一个指向您的视图的 url(仅检查路径的开头,这应该是相同的),然后在您的视图中解析
request.path
。另一方面,如果您确实有许多不同组合的可选过滤器参数,那么最好的解决方案通常是通过
GET
参数进行过滤,特别是如果用于过滤的 url 不需要针对任何搜索引擎进行优化...You could also make just one url (that only checks the start of the path, that should be the same) pointing to your view and then parse
request.path
in your view.On the other hand, if you have really many optional filter parameters in various combinations the best solution is very often to do th filtering via
GET
-parameters, especially if the urls used for filtering don't need to be optimized for any search engine...尝试在 urls.py 中使用类似的内容:
Try use something like that in your urls.py: