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 पास हो जाए, तो मैं इसका उपयोग कर सकूं।

जैसा कि यह इस समय खड़ा है, मुझे एक 404 मिलता है जब मैं बिना project_idपैरामीटर के URL का उपयोग करता हूं ।

जवाबों:


381

कई दृष्टिकोण हैं।

एक regex में एक गैर-कैप्चरिंग समूह का उपयोग करना है : (?:/(?P<title>[a-zA-Z]+)/)?
एक Regex 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
बुरहान खालिद

4
@ युजी - क्या आप प्रत्येक url पैटर्न का नाम बदलकर उलट समस्या को हल नहीं कर सकते?
टेड

8
क्या हम हर दृश्य को एक ही नाम दे सकते हैं?
यूजीन

2
@ Yuji'Tomita'Tomita मुझे पता है, इसलिए यूजीन के प्रश्न का उत्तर दुर्भाग्य से है, नहीं, हम समान रूप से एक ही नाम के साथ कई विचार नहीं कर सकते, भले ही हम उन्हें वैकल्पिक मापदंडों को प्राप्त करने के तरीके के रूप में लागू कर रहे हों।
nnyby

2
@ यूजीन हाँ, हम एक ही नाम के साथ दो url लगा सकते हैं, उल्टा चालाकी से जो भी लागू होगा, वह आर्गन के आधार पर लागू होगा
अर्पित सिंह

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

यह एक बहुत अधिक DRY है (आप जिस productक्वार का नाम बदलना चाहते थे product_id, आपको केवल पंक्ति 4 को बदलना होगा, और यह नीचे दिए गए URL को प्रभावित करेगा।

Django 1.8 और इसके बाद के संस्करण के लिए संपादित


1
नेस्टेड अच्छा है। इसके अलावा, यह आपके कोड में अलग-अलग URL वर्गों को अधिक स्पष्ट रूप से (इंडेंट के उपयोग के कारण) अलग करता है
पैट्रिक

नेस्टेड के साथ समस्या यह है कि यदि आपके पास कई वैकल्पिक पैरामीटर हैं, तो आप अंत में DRY नहीं कर रहे हैं, उदाहरण के लिए, 3 वैकल्पिक पैरामीटर, आपके पास संभावित URL के 8 अलग-अलग संयोजन हैं। आपको पैरामीटर 1 घटित होना है, पैरामीटर 1 घटित नहीं है, लेकिन पैरामीटर 2 घटित हो रहा है, और पैरामीटर्स 1 और 2 घटित नहीं हो रहा है, लेकिन पैरामीटर 3 घटित हो रहा है। URL पैराग्राफ कई वैकल्पिक मापदंडों के साथ एक स्ट्रिंग की तुलना में पढ़ने के लिए बहुत कठिन होगा। वैकल्पिक पैरामीटर सबस्ट्रिंग के लिए प्रतीकात्मक स्थिरांक का उपयोग करना पढ़ने में बहुत आसान होगा, और सिर्फ एक URL होगा।
बोगाटेयर

मुझे लगता है कि आप सही हैं, लेकिन यह खराब दृश्य / URL डिज़ाइन के परिणामस्वरूप अधिक है। इस उदाहरण को बहुत बेहतर होने के लिए फिर से तैयार किया जा सकता है।
जैकब वेलेंटा सेप

'फ्लैट नेस्टेड से बेहतर है'
pjdavis

30

उपयोग करने के लिए और भी सरल है:

(?P<project_id>\w+|)

"(ए | बी)" का अर्थ है एक या बी, इसलिए आपके मामले में यह एक या एक से अधिक शब्द अक्षर (\ w +) या कुछ भी नहीं होगा।

तो ऐसा लगेगा:

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

9
मुझे इस समाधान की सादगी पसंद है, लेकिन सावधान रहें: ऐसा करने से, दृष्टिकोण अभी भी तर्क के लिए एक मूल्य प्राप्त करेगा, जो होगा None। इसका मतलब है कि आप इसके लिए दृश्य के हस्ताक्षर में एक डिफ़ॉल्ट मूल्य पर भरोसा नहीं कर सकते हैं: आपको इसे स्पष्ट रूप से अंदर परीक्षण करना होगा और परिणाम में असाइन करना होगा।
Anto

यह मैं =) के लिए देख रहा था
माइक ब्रायन ओलिवर

3
मामले में अंतिम स्लैश के बारे में क्या project_id मौजूद नहीं है?
इमुखुश

आप सिर्फ एक जोड़ सकते हैं? स्लैश के बाद या प्रोजेक्ट_ड पैटर्न में स्लैश को शामिल करें
जुआन जोस ब्राउन

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()आप का उपयोग करके भी वैकल्पिक तर्क के साथ अतिरिक्त तर्क पारित कर सकते हैं kwargsजो कि प्रकार का है dict। इस स्थिति में आपके विचार को विशेषता के लिए डिफ़ॉल्ट की आवश्यकता नहीं होगी project_id:

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

यह सबसे हालिया Django संस्करण में कैसे किया जाता है , इसके लिए URL भेजने के बारे में आधिकारिक डॉक्स देखें ।


1
मुझे लगता है कि आपने अपने कोड में project_id और product_id मिलाया है, है ना?
एंड्रियास बर्गस्ट्रॉम

@ AndreasBergström कि बाहर इशारा करने के लिए बहुत बहुत धन्यवाद! आप इस बारे में काफी सही हैं! इसे जल्दबाज़ी में ठीक किया, लेकिन बाद में इस पर दूसरा नज़र डाला जाएगा। उम्मीद है कि अब ठीक है! project_idडिफ़ॉल्ट का उपयोग करने के मामले में पथ में अभी भी था dict। इससे प्रतीत होता है कि अजीब व्यवहार हो सकता है, क्योंकि dictवसीयत में प्रदान किए गए तर्क का हमेशा उपयोग किया जाएगा (यदि मुझे सही याद है)।
जोजो

@jojo का मतलब है कि 2 विकल्प में एक 'project_config / foo / bar' स्वचालित रूप से {'project_id': 'bar'} kwargs को पास कर देगा?
मूल BBQ सॉस

9

सोचा था कि मैं जवाब में थोड़ा जोड़ दूंगा।

यदि आपके पास कई URL परिभाषाएँ हैं, तो आपको उनमें से प्रत्येक को अलग से नाम देना होगा। इसलिए जब आप रिवर्स कॉलिंग करते हैं तो लचीलापन खो जाता है क्योंकि एक रिवर्स एक पैरामीटर की अपेक्षा करेगा जबकि दूसरा नहीं करेगा।

वैकल्पिक पैरामीटर को समायोजित करने के लिए रेगेक्स का उपयोग करने का दूसरा तरीका:

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+)/)?$']
पैट्रिक

2

Django = 2.2

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

0

उपयोग ? अच्छी तरह से काम करें, आप पाइथेक्स पर जांच कर सकते हैं । दृश्य विधियों की परिभाषा में पैरामीटर * आर्ग्स और ** क्वार्ग्स जोड़ना याद रखें

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.