Django isteğe bağlı url parametreleri


161

Ben böyle bir Django URL var:

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

Sorun project_idparametre isteğe bağlı olmasını istiyorum olmasıdır .

İstediğim /project_config/ve /project_config/12345abdce/böylece eşit geçerli URL modelleri olmak eğer project_id geçirilir, daha sonra bunu kullanabilir.

Şu anda durduğu gibi, URL'ye project_idparametre olmadan eriştiğimde 404 alıyorum .

Yanıtlar:


381

Birkaç yaklaşım var.

Bunlardan biri normal ifadede yakalamayan bir grup kullanmaktır: (?:/(?P<title>[a-zA-Z]+)/)?
Regex Django URL Jetonunu İsteğe Bağlı Yapma

Takip edilmesi daha kolay olan başka bir yol da, hepsi aynı görünüme işaret eden ihtiyaçlarınızla eşleşen birden fazla kurala sahip olmaktır.

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),
)

Görünümünüzde ayrıca isteğe bağlı URL parametresi için bir varsayılan ayarlamanız gerektiğini veya bir hata alacağınızı unutmayın:

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

68
Birden çok yol seçeneği için oy verin. +1
Burhan Khalid

4
@Yuji - tersine çevirme sorununu her URL modelini adlandırarak çözemez misiniz?
Ted

8
her görünüme aynı adı verebilir miyiz?
eugene

2
@ Yuji'Tomita'Tomita Biliyorum, bu yüzden eugene'nin sorusunun cevabı maalesef, isteğe bağlı parametreler elde etmenin bir yolu olarak uygulasak bile aynı ada sahip birden fazla görüşe sahip olamayız.
nnyby

2
@eugene Evet aynı ada sahip iki urlimiz olabilir, tersine çevirme, argümanlara bağlı olarak hangisinin uygulanabilir olduğunu akıllıca seçer
Arpit Singh

37

İç içe rotalar kullanabilirsiniz

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")
        ])),
    ])),
]

Bu çok daha KURU ( productkwarg'ı yeniden adlandırmak istediğinizi product_id, yalnızca 4. satırı değiştirmeniz gerektiğini ve aşağıdaki URL'leri etkileyeceğini varsayalım .

Django 1.8 ve üstü için düzenlendi


1
İç içe iyi. Ayrıca, kodunuzdaki farklı URL bölümlerini daha net bir şekilde ayırır (girintilerin kullanımı nedeniyle)
Patrick

İç içe yerleştirme ile ilgili sorun, birden fazla isteğe bağlı parametreniz varsa, o zaman DRY olmamanızdır, çünkü 3 isteğe bağlı parametre ile 8 farklı olası URL kombinasyonunuz vardır. Parametre 1 gerçekleşiyor, parametre 1 oluşmuyor, ancak parametre 2 oluşuyor ve parametre 1 ve 2 oluşmuyor, ancak parametre 3 oluşuyor. URL paragrafı, birden fazla isteğe bağlı parametreye sahip tek bir dizeden okumaktan çok daha zor olacaktır. İsteğe bağlı parametre alt dizeleri için sembolik sabitlerin kullanılması okumayı çok kolaylaştıracak ve yalnızca bir URL olacaktır.
Bogatyr

Bence haklısın, ama bu daha çok kötü görünüm / URL tasarımının bir sonucu. Bu örnek çok daha iyi olacak şekilde elden geçirilebilir.
Jacob Valenta

'flat is nested than better'
pjdavis

30

Daha da basit kullanımı:

(?P<project_id>\w+|)

"(A | b)", a veya b anlamına gelir; bu durumda, bir veya daha fazla kelime karakteri (\ w +) veya hiçbir şey olmaz.

Yani şöyle görünecektir:

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

9
Bu çözümün basitliğini seviyorum, ancak dikkat edin: Bunu yaparak, görünüm yine de argüman için bir değer alacaktır None. Bunun için görünümün imzasında varsayılan bir değere güvenemeyeceğiniz anlamına gelir: bunu açıkça test etmeli ve sonuç olarak atamalısınız.
Anto

Bu aradım =)
Mike Brian Olivera

3
project_id öğesinin mevcut olmaması durumunda son eğik çizgi ne olacak?
iamkhush

Sadece? eğik çizgiden sonra ya da sadece eğik çizgiyi project_id modeline dahil et
Juan José Brown

18

Django> 2.0 sürümü :

Bu yaklaşım, Yuji 'Tomita' Tomita'nın Cevabı'nda verilen yaklaşımla özdeştir . Ancak sözdizimi etkilenir:

# 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
    ...

Kullanarak , isteğe bağlı türden bağımsız değişkene sahip bir görünüme ekstra bağımsız değişkenlerpath() de iletebilirsiniz . Bu durumda, görünümünüzün özellik için varsayılana ihtiyacı yoktur :kwargsdictproject_id

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

Bunun en son Django sürümünde nasıl yapıldığını öğrenmek için URL gönderme ile ilgili resmi belgelere bakın .


1
Kodunuzda project_id ve product_id kodlarını karıştırdığınızı düşünüyorum, değil mi?
Andreas Bergström

@ AndreasBergström bunu işaret ettiğiniz için çok teşekkürler! bu konuda oldukça haklısın! Aceleyle düzeltildi, ancak daha sonra 2. kez bakacak. Umarım şimdi iyi! Ayrıca project_ida'nın varsayılan kullanılması durumunda da yoldaydı dict. Bu, garip davranışlara yol açabilir, çünkü verilen argüman dicther zaman kullanılacaktır (doğru hatırlarsam).
jojo

@jojo Bu, 2. seçenekteki 'project_config / foo / bar' ifadesinin otomatik olarak {'project_id': 'bar'} kwarg'ları görünüme geçireceği anlamına mı geliyor?
Orijinal Barbekü Sosu

9

Cevaba biraz ekleyeceğimi düşündüm.

Birden fazla URL tanımınız varsa, her birini ayrı ayrı adlandırmanız gerekir. Böylece geri çağırırken esnekliği kaybedersiniz, çünkü bir geri dönüşüm bir parametre beklerken diğeri beklemez.

İsteğe bağlı parametreyi barındırmak için regex kullanmanın başka bir yolu:

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

2
Django 1.6'da bu benim için bir istisna oluşturuyor. 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

2

Django = 2.2

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

0

Kullan? iyi çalışır, pythex'i kontrol edebilirsiniz . Görüntüleme yöntemlerinin tanımına * args ve ** kwargs parametrelerini eklemeyi unutmayın

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.