Django-オプションのURLパラメーターの場合は正規表現
-
28-10-2019 - |
質問
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つのフィルターを使用すると、これは管理不能になります。
私が達成したいことをするための最良の方法は何ですか?
解決
1つの方法は、正規表現に指定されたすべてのフィルターを単一の文字列として読み取り、ビュー内の個々の値に分割することです。
次のURLを思いつきました。
(r'^(?P<city>[^/]+)/(?P<state>[^/]+)(?P<filters>(?:/[^/]+/[^/]+)*)/?$',
'views.my_view'),
必要な都市と州に一致するのは簡単です。 filters
部分はもう少し複雑です。内側の部分 - (?:/[^/]+/[^/]+)*
- フォームで与えられたフィルターを一致させます /name/value
. 。しかし *
定量装置(すべてのPython正規表現の数量ファイヤーと同様)は、見つかった最後の一致のみを返します。したがって、URLがあった場合 /radius/80/company/mycompany/
それだけ 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)
これについて注意すべき2つのこと。まず、未知のフィルターエントリをビューに入れることができます。例えば、 /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)
他のヒント
これは絶対にパラメーターを取得するためのユースケースです。あなたのurlconfはただなければなりません /city/state/
, 、次に、変数を取得すると、さまざまなフィルターが最後に進みます。
/city/state/?radius=5&company=google
今、あなたの見解では、あなたは受け入れます city
と state
通常のパラメーターとしてですが、他のすべては request.GET
querydict。
また、1つのURL(パスの開始のみをチェックするだけで、同じであるはずです)を作成して、ビューを指してから解析することもできます。 request.path
あなたの見解で。一方、さまざまな組み合わせに非常に多くのオプションのフィルターパラメーターがある場合、最良のソリューションは非常に頻繁にフィルタリングを行うことです。 GET
- 特にフィルタリングに使用されるURLが検索エンジンに最適化する必要はない場合...
あなたのurls.pyでそのようなものを使用してみてください:
url(r'^(?P<city>[^/]+)/(?P<state>[^/]+)/(radius/(?P<miles>[^/]+)/|company/(?P<company_name>[^/]+)/)*$', 'view')