DjangoのオプションのURLパラメータ


161

私はこのようなDjango URLを持っています:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

views.py:

def ProjectConfig(request, product, project_id=None, template_name='project.html'):
    ...
    # do stuff

問題は、project_idパラメーターをオプションにすることです。

私が欲しい/project_config//project_config/12345abdce/なるよう、均等に有効なURLパターンであることを場合 project_id渡され、その後、私はそれを使用することができます。

現時点では、project_idパラメータなしでURLにアクセスすると404が返されます。

回答:


381

いくつかのアプローチがあります。

1つは、正規表現で非キャプチャグループを使用することです。正規表現 (?:/(?P<title>[a-zA-Z]+)/)?
Django URLトークンをオプションにする

別の、より簡単な方法は、ニーズに一致する複数のルールを用意し、すべて同じビューを指すようにすることです。

urlpatterns = patterns('',
    url(r'^project_config/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$', views.foo),
)

ビューでオプションのURLパラメータのデフォルトも設定する必要があることに注意してください。そうしないと、エラーが発生します。

def foo(request, optional_parameter=''):
    # Your code goes here

68
複数ルートオプションに投票します。+1
Burhan Khalid 2013年

4
@Yuji-各URLパターンに名前を付けることで逆転の問題を解決できませんか?
2013年

8
すべてのビューに同じ名前を付けることができますか?
ユージーン2014年

2
@ Yuji'Tomita'Tomita知っているので、残念ながらeugeneの質問への答えは、オプションのパラメーターを取得する方法として実装している場合でも、同じ名前の複数のビューを持つことはできません。
nnyby 14

2
@eugeneはい、同じ名前の2つのURLを使用できます。逆にすると、引数に応じて適切な方がスマートに取得されます
Arpit Singh

37

ネストされたルートを使用できます

Django <1.8

urlpatterns = patterns(''
    url(r'^project_config/', include(patterns('',
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include(patterns('',
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ))),
    ))),
)

Django> = 1.8

urlpatterns = [
    url(r'^project_config/', include([
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include([
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ])),
    ])),
]

これはproductはるかに乾燥しています(たとえば、kwargの名前をに変更したいとします。4 product_id行目を変更するだけで、以下のURLに影響します。

Django 1.8以降用に編集


1
入れ子がいいです。また、コード内のさまざまなURLセクションをより明確に分離します(インデントを使用しているため)
Patrick

入れ子の問題は、複数のオプションパラメータがある場合、DRYにならないことです。たとえば、3つのオプションパラメータを使用すると、考えられるURLの組み合わせが8つあります。パラメータ1が発生する、パラメータ1が発生しないがパラメータ2が発生する、パラメータ1と2は発生しないがパラメータ3が発生するを処理する必要があります。URL段落は、複数のオプションパラメータを持つ単一の文字列よりもはるかに読みにくくなります。オプションのパラメーターのサブストリングに記号定数を使用すると、非常に読みやすくなり、URLは1つだけになります。
Bogatyr

私はあなたが正しいと思いますが、それはビュー/ URLのデザインが悪いことが原因です。この例は、より良くなるように作り直すことができます。
Jacob Valenta

「ネストよりもフラットの方が良い」
pjdavis

30

さらに簡単なのは以下を使用することです:

(?P<project_id>\w+|)

「(a | b)」はaまたはbを意味するので、あなたの場合、それは1つ以上の単語文字(\ w +)か、何もないことになります。

したがって、次のようになります。

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

9
私はこのソリューションの単純さが好きですが、注意してください。そうすることで、ビューは引数の値を受け取りますNone。これは、ビューの署名のデフォルト値に依存することができないことを意味します。内部で明示的にテストして、結果として割り当てる必要があります。
Anto 14

これは私が探していた=)
マイク・ブライアン・オリベラ2017

3
project_idが存在しない場合の最後のスラッシュはどうですか?
iamkhush 2017年

あなただけを追加できますか?スラッシュの後、またはスラッシュをproject_idパターンに含める
JuanJoséBrown

18

Django> 2.0バージョン

このアプローチは、「冨田裕二」という富田の回答に記載されているアプローチと本質的に同じです。ただし、影響を受けるのは構文です。

# URLconf
...

urlpatterns = [
    path(
        'project_config/<product>/',
        views.get_product, 
        name='project_config'
    ),
    path(
        'project_config/<product>/<project_id>/',
        views.get_product,
        name='project_config'
    ),
]


# View (in views.py)
def get_product(request, product, project_id='None'):
    # Output the appropriate product
    ...

を使用path()すると、タイプのオプションの引数を使用して、ビューに追加の引数を渡すこともできます。この場合、ビューには属性のデフォルトは必要ありません。kwargsdictproject_id

    ...
    path(
        'project_config/<product>/',
        views.get_product,
        kwargs={'project_id': None},
        name='project_config'
    ),
    ...

最新のDjangoバージョンでこれがどのように行われるかについては、URLディスパッチに関する公式ドキュメントを参照してください。


1
コードでproject_idとproduct_idを混同していると思いますよね?
AndreasBergström19年

@AndreasBergströmは指摘してくれてありがとう!あなたはこれについてかなり正しいです!急いで修正しましたが、後で2回目に見ていきます。今は大丈夫だと思います!project_idを使用したデフォルトの場合、パスにはまだ静止画もありましたdict。で提供された引数dictが常に使用されるため(これを正しく覚えていれば)、これは一見奇妙な動作につながる可能性があります。
ジョジョ

@jojo 2番目のオプションの 'project_config / foo / bar'が{'project_id': 'bar'} kwargsを自動的にビューに渡すことを意味しますか?
オリジナルのBBQソース

9

私は答えに少し追加すると思いました。

複数のURL定義がある場合は、それぞれに個別に名前を付ける必要があります。したがって、リバースを呼び出すときに柔軟性が失われます。これは、1つのリバースがパラメーターを期待する一方で、もう1つはそうではないためです。

正規表現を使用してオプションのパラメーターに対応する別の方法:

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'

2
Django 1.6では、これは私にとって例外をスローします。私はそれから離れたままにしますReverse for 'edit_too_late' with arguments '()' and keyword arguments '{'pk': 128}' not found. 1 pattern(s) tried: ['orders/cannot_edit/((?P<pk>\\d+)/)?$']
Patrick 14年

2

Django = 2.2

urlpatterns = [
    re_path(r'^project_config/(?:(?P<product>\w+)/(?:(?P<project_id>\w+)/)/)?$', tool.views.ProjectConfig, name='project_config')
]

0

使用する ?うまく機能するなら、pythexで確認できます。ビューメソッドの定義にパラメータ* argsおよび** kwargsを追加することを忘れないでください

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.