django - 可选url参数的regex [英] django - regex for optional url parameters

查看:150
本文介绍了django - 可选url参数的regex的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在django中有一个可以接受多个不同过滤器参数的视图,但它们都是可选的。如果我有6个可选过滤器,我真的必须为6的每个组合写入URL,还是有一种方法来定义url的哪些部分是可选的?

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?

为了给你一个只有2个过滤器的例子,我可以拥有所有这些URL的可能性:

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>/

所有这些网址都指向视图和唯一必需的参数是城市和州。有6个过滤器,这变得无法管理。

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?

推荐答案

一种方法是使正则表达式读取所有给定的过滤器作为单个字符串,然后将其分割为视图中的各个值。

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.

我想出了以下URL:

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

匹配所需的城市和州是容易的。 过滤器部分有点复杂。内部部分 - (?:/ [^ /] + / [^ /] +)* - 匹配以 / name /值。然而, * 量词(像所有Python正则表达式量词)只会返回最后一次匹配 - 所以如果url是 / radius / 80 / company / mycompany / 只有 company / mycompany 将被存储。相反,我们告诉它不要在开始时捕获单个值(?:),并将其放在捕获块中,该捕获块将所有过滤器值存储为单个字符串。

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/ only company/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.

视图逻辑非常简单。请注意,正则表达式将只匹配过滤器对,因此 / company / mycompany / radius / 将不匹配。这意味着我们可以放心地假设我们有一对价值观。我测试过的视图如下:

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:

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 是有效的。上面的视图代码忽略这些,但您可能想要向用户报告错误。如果是这样,将代码更改为

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 to

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

剩余的$ code>过滤器字典是您可以抱怨的未知值。

Any entries remaining in the filters dictionary are unknown values about which you can complain.

其次,如果用户重复过滤器,最后一个值将被使用。例如, / radius / 80 / radius / 50 将半径设置为50.如果要检测到此问题,则需要先扫描值列表之前转换为字典:

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:

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

这篇关于django - 可选url参数的regex的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆