Django में एक पृष्ठ पर कई रूपों को संभालने का उचित तरीका


200

मेरे पास दो रूपों की अपेक्षा करने वाला एक टेम्पलेट पृष्ठ है। यदि मैं सिर्फ एक फॉर्म का उपयोग करता हूं, तो चीजें इस विशिष्ट उदाहरण में ठीक हैं:

if request.method == 'POST':
    form = AuthorForm(request.POST,)
    if form.is_valid():
        form.save()
        # do something.
else:
    form = AuthorForm()

यदि मैं कई रूपों के साथ काम करना चाहता हूं, लेकिन मैं यह कैसे बताऊं कि मैं केवल एक ही फॉर्म जमा कर रहा हूं और दूसरा नहीं (यानी यह अभी भी अनुरोध है। PST लेकिन मैं केवल उस फॉर्म को प्रोसेस करना चाहता हूं जिसके लिए सबमिट करना है हो गई)?


यह उत्तर के आधार पर समाधान है जहाँ अपेक्षित फॉर्मेज़ और बैनडफ़्रेज़ विभिन्न रूपों के लिए सबमिट बटन के नाम हैं और अपेक्षित फॉर्मरेज़फॉर्म और बैन्डफ़्रेज़फॉर्म फॉर्म हैं।

if request.method == 'POST':
    if 'bannedphrase' in request.POST:
        bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
        if bannedphraseform.is_valid():
            bannedphraseform.save()
        expectedphraseform = ExpectedPhraseForm(prefix='expected')
    elif 'expectedphrase' in request.POST:
        expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
        if expectedphraseform.is_valid():
            expectedphraseform.save() 
        bannedphraseform = BannedPhraseForm(prefix='banned')
else:
    bannedphraseform = BannedPhraseForm(prefix='banned')
    expectedphraseform = ExpectedPhraseForm(prefix='expected')

2
क्या आपके समाधान के साथ कोई तार्किक त्रुटि नहीं है? यदि आप 'बैनडफ्रैस' पोस्ट करते हैं, तो उम्मीद के मुताबिक आबादी नहीं मिलेगी।
Ztyx

2
यह एक समय में केवल एक रूप को संभालेगा, यह सवाल एक ही समय में कई रूपों को संभालने के बारे में है
चमकते हुए

जवाबों:


140

आपके पास कुछ विकल्प हैं:

  1. दो रूपों के लिए कार्रवाई में अलग-अलग URL डालें। फिर आपके पास दो अलग-अलग रूपों से निपटने के लिए दो अलग-अलग दृश्य कार्य होंगे।

  2. POST डेटा से सबमिट बटन मान पढ़ें। आप बता सकते हैं कि किस सबमिट बटन पर क्लिक किया गया था: मैं एकाधिक सबमिट बटन django फॉर्म कैसे बना सकता हूं?


5
3) निर्धारित करें कि POST डेटा में फ़ील्ड नामों से कौन सा फ़ॉर्म सबमिट किया गया है। कुछ छिपे हुए आदानों को शामिल करें यदि आपके पास सभी विशिष्ट मान रिक्त नहीं होने के साथ अद्वितीय फ़ील्ड नहीं हैं।
डेनिस ओटकिडैच

13
4) फॉर्म की पहचान करने वाला एक छिपा हुआ क्षेत्र जोड़ें और अपने विचार में इस क्षेत्र का मूल्य जांचें।
सोवियुत

यदि संभव हो तो मैं POST डेटा को प्रदूषित करने से दूर रहूंगा। मैं इसके बजाय फॉर्म एक्शन यूआरएल में एक जीईटी पैरामीटर जोड़ने की सलाह देता हूं।
पाइजेक

6
# 1 वास्तव में यहाँ तुम्हारा सबसे अच्छा दांव है। आप छिपे हुए क्षेत्रों के साथ POST को प्रदूषित नहीं करना चाहते हैं और न ही आप अपने टेम्पलेट और / या फ़ॉर्म के बारे में अपने विचार को समझना चाहते हैं।
उल्का पिंड

5
@meteorainer यदि आप नंबर एक का उपयोग करते हैं, तो क्या माता-पिता के विचारों में उन त्रुटियों को पारित करने का एक तरीका है जो इनको इंस्टेंट करता है, या तो संदेश ढांचे या क्वेरी स्ट्रिंग का उपयोग किए बिना? यह उत्तर निकटतम लगता है, लेकिन यहां अभी भी दोनों रूपों को संभालने वाला एक दृश्य है: stackoverflow.com/a/21271659/2532070
YPCrumble

45

भविष्य के संदर्भ के लिए एक विधि कुछ इस तरह है। bannedphraseform पहला रूप है और अपेक्षितphraseform दूसरा है। यदि पहले एक को मारा जाता है, तो दूसरा छोड़ दिया जाता है (जो इस मामले में एक उचित धारणा है):

if request.method == 'POST':
    bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
    if bannedphraseform.is_valid():
        bannedphraseform.save()
else:
    bannedphraseform = BannedPhraseForm(prefix='banned')

if request.method == 'POST' and not bannedphraseform.is_valid():
    expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
    bannedphraseform = BannedPhraseForm(prefix='banned')
    if expectedphraseform.is_valid():
        expectedphraseform.save()

else:
    expectedphraseform = ExpectedPhraseForm(prefix='expected')

7
उपसर्ग का उपयोग करना = वास्तव में 'उचित तरीका' है
रिच

उपसर्ग- kwarg ने किया काम, अच्छा!
स्टीफन होयर

1
उन उपसर्गों के साथ महान विचार, हमने अब उन का उपयोग किया और वे एक आकर्षण की तरह काम करते हैं। लेकिन फिर भी हमें यह पता लगाने के लिए एक छिपे हुए फ़ील्ड को सम्मिलित करना था कि कौन सा फ़ॉर्म सबमिट किया गया था, क्योंकि दोनों फॉर्म एक लाइटबॉक्स में हैं (प्रत्येक एक अलग में)। क्योंकि हमें सही लाइटबॉक्स को फिर से खोलने की आवश्यकता है, हमें यह जानना आवश्यक है कि कौन सा फ़ॉर्म सबमिट किया गया था, और फिर यदि पहले फ़ॉर्म में कोई सत्यापन त्रुटियाँ हैं, तो दूसरा स्वतः ही जीत जाता है और पहला फ़ॉर्म रीसेट हो जाता है, हालाँकि हमें अभी भी त्रुटियों को प्रदर्शित करने की आवश्यकता है पहला रूप। बस सोचा था कि आपको पता होना चाहिए
Enduriel

क्या इस प्रतिरूप को तीन रूपों के मामले में विस्तार देना क्लिंक नहीं होगा? जैसे, पहले फॉर्म से is_valid () की जाँच के साथ, फिर पहले दो, आदि ... हो सकता है handled = Falseकि Trueएक संगत प्रपत्र मिलने पर बस अपडेट हो जाए?
बिंकी

14

Django के क्लास आधारित विचार एक सामान्य फॉर्मव्यू प्रदान करते हैं लेकिन सभी इरादों और उद्देश्यों के लिए इसे केवल एक रूप को संभालने के लिए डिज़ाइन किया गया है।

Django के सामान्य विचारों का उपयोग करते हुए एक ही लक्ष्य कार्रवाई url के साथ कई रूपों को संभालने का एक तरीका है, जैसा कि नीचे दिखाया गया है, 'TemplateView' का विस्तार करना; मैं अक्सर इस दृष्टिकोण का उपयोग करता हूं कि मैंने इसे एक ग्रहण आईडीई टेम्पलेट में बनाया है।

class NegotiationGroupMultifacetedView(TemplateView):
    ### TemplateResponseMixin
    template_name = 'offers/offer_detail.html'

    ### ContextMixin 
    def get_context_data(self, **kwargs):
        """ Adds extra content to our template """
        context = super(NegotiationGroupDetailView, self).get_context_data(**kwargs)

        ...

        context['negotiation_bid_form'] = NegotiationBidForm(
            prefix='NegotiationBidForm', 
            ...
            # Multiple 'submit' button paths should be handled in form's .save()/clean()
            data = self.request.POST if bool(set(['NegotiationBidForm-submit-counter-bid',
                                              'NegotiationBidForm-submit-approve-bid',
                                              'NegotiationBidForm-submit-decline-further-bids']).intersection(
                                                    self.request.POST)) else None,
            )
        context['offer_attachment_form'] = NegotiationAttachmentForm(
            prefix='NegotiationAttachment', 
            ...
            data = self.request.POST if 'NegotiationAttachment-submit' in self.request.POST else None,
            files = self.request.FILES if 'NegotiationAttachment-submit' in self.request.POST else None
            )
        context['offer_contact_form'] = NegotiationContactForm()
        return context

    ### NegotiationGroupDetailView 
    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)

        if context['negotiation_bid_form'].is_valid():
            instance = context['negotiation_bid_form'].save()
            messages.success(request, 'Your offer bid #{0} has been submitted.'.format(instance.pk))
        elif context['offer_attachment_form'].is_valid():
            instance = context['offer_attachment_form'].save()
            messages.success(request, 'Your offer attachment #{0} has been submitted.'.format(instance.pk))
                # advise of any errors

        else 
            messages.error('Error(s) encountered during form processing, please review below and re-submit')

        return self.render_to_response(context)

HTML टेम्पलेट निम्नलिखित प्रभाव के लिए है:

...

<form id='offer_negotiation_form' class="content-form" action='./' enctype="multipart/form-data" method="post" accept-charset="utf-8">
    {% csrf_token %}
    {{ negotiation_bid_form.as_p }}
    ...
    <input type="submit" name="{{ negotiation_bid_form.prefix }}-submit-counter-bid" 
    title="Submit a counter bid"
    value="Counter Bid" />
</form>

...

<form id='offer-attachment-form' class="content-form" action='./' enctype="multipart/form-data" method="post" accept-charset="utf-8">
    {% csrf_token %}
    {{ offer_attachment_form.as_p }}

    <input name="{{ offer_attachment_form.prefix }}-submit" type="submit" value="Submit" />
</form>

...

1
मैं इसी समस्या से जूझ रहा हूं और प्रत्येक पोस्ट को एक अलग रूप दृश्य में संसाधित करने और फिर सामान्य टेम्पलेट दृश्य पर पुनर्निर्देशित करने का एक तरीका खोजने की कोशिश कर रहा था। बिंदु सामग्री के लिए टेम्पलेट दृश्य को जिम्मेदार बनाने और बचत के लिए प्रपत्र दृश्य बनाने के लिए है। सत्यापन हालांकि एक समस्या है। सत्र के रूपों को सहेजने से मेरा मन पार हो गया ... फिर भी एक स्वच्छ समाधान की तलाश में।
डेनियल बर्नार्डिनी

14

मुझे ऐसे कई रूपों की आवश्यकता थी जो स्वतंत्र रूप से एक ही पृष्ठ पर मान्य हैं। मुख्य अवधारणाएँ जो मुझे याद आ रही थीं, 1 थीं) सबमिट बटन नाम के लिए उपसर्ग का उपयोग करके और 2) एक अनबाउंड फॉर्म सत्यापन को ट्रिगर नहीं करता है। यदि यह किसी और की मदद करता है, तो यहां @ adam-nelson और @ daniel-sokolowski द्वारा दिए गए जवाबों और @zeraien ( https://stoveroverflow.com/a/17303480) द्वारा दिए गए उत्तरों के आधार पर AForm और BForm के दो सरलीकृत उदाहरण दिए गए हैं। / 2680349 ):

# views.py
def _get_form(request, formcls, prefix):
    data = request.POST if prefix in request.POST else None
    return formcls(data, prefix=prefix)

class MyView(TemplateView):
    template_name = 'mytemplate.html'

    def get(self, request, *args, **kwargs):
        return self.render_to_response({'aform': AForm(prefix='aform_pre'), 'bform': BForm(prefix='bform_pre')})

    def post(self, request, *args, **kwargs):
        aform = _get_form(request, AForm, 'aform_pre')
        bform = _get_form(request, BForm, 'bform_pre')
        if aform.is_bound and aform.is_valid():
            # Process aform and render response
        elif bform.is_bound and bform.is_valid():
            # Process bform and render response
        return self.render_to_response({'aform': aform, 'bform': bform})

# mytemplate.html
<form action="" method="post">
    {% csrf_token %}
    {{ aform.as_p }}
    <input type="submit" name="{{aform.prefix}}" value="Submit" />
    {{ bform.as_p }}
    <input type="submit" name="{{bform.prefix}}" value="Submit" />
</form>

मुझे लगता है कि यह वास्तव में एक स्वच्छ समाधान है। धन्यवाद।
छैनीताल

मुझे वास्तव में यह समाधान पसंद है। एक प्रश्न: क्या कोई कारण है कि _get_form () MyView वर्ग का एक तरीका नहीं है?
हवाई

1
@ AndréTerra यह निश्चित रूप से हो सकता है, हालाँकि आप शायद इसे जेनेरिक क्लास में रखना चाहते हैं, जो टेम्प्लेट व्यू से विरासत में मिला है ताकि आप इसे अन्य दृश्यों में पुनः उपयोग कर सकें।
यबेंडाना

1
यह एक बेहतरीन उपाय है। मुझे __get_form की एक पंक्ति बदलने की आवश्यकता थी ताकि यह काम करे: data = request.POST if prefix in next(iter(request.POST.keys())) else None अन्यथा inकाम नहीं किया।
लैप्सपोडिया

एकल <फॉर्म> टैग का उपयोग करके इस तरह के आवश्यक फ़ील्ड की आवश्यकता विश्व स्तर पर होती है जब उन्हें प्रति-प्रपत्र होना चाहिए जिसके आधार पर सबमिट बटन पर क्लिक किया गया था। दो <फॉर्म> टैग (एक ही कार्रवाई के साथ) में विभाजित करना काम करता है।
फ्लैश

3

मेरे समाधान को साझा करना चाहता था जहाँ Django प्रपत्रों का उपयोग नहीं किया जा रहा है। मेरे पास एक ही पृष्ठ पर एकाधिक फ़ॉर्म तत्व हैं और मैं सभी रूपों से सभी POST अनुरोधों को प्रबंधित करने के लिए एकल दृश्य का उपयोग करना चाहता हूं।

मैंने जो किया है, मैंने एक अदृश्य इनपुट टैग पेश किया है ताकि मैं यह देखने के लिए कि कौन सा फॉर्म सबमिट किया गया है, मैं एक पैरामीटर पास कर सकूं।

<form method="post" id="formOne">
    {% csrf_token %}
   <input type="hidden" name="form_type" value="formOne">

    .....
</form>

.....

<form method="post" id="formTwo">
    {% csrf_token %}
    <input type="hidden" name="form_type" value="formTwo">
   ....
</form>

views.py

def handlemultipleforms(request, template="handle/multiple_forms.html"):
    """
    Handle Multiple <form></form> elements
    """
    if request.method == 'POST':
        if request.POST.get("form_type") == 'formOne':
            #Handle Elements from first Form
        elif request.POST.get("form_type") == 'formTwo':
            #Handle Elements from second Form

मुझे लगता है कि यह एक अच्छा और आसान तरीका है
Shedrack

2

यह थोड़ा देर से है, लेकिन यह सबसे अच्छा समाधान है जो मैंने पाया। आप प्रपत्र नाम और उसकी कक्षा के लिए एक लुक-अप शब्दकोश बनाते हैं, आपको फ़ॉर्म को पहचानने के लिए एक विशेषता भी जोड़ना होगा, और आपके विचारों में आपको इसे एक छिपे हुए फ़ील्ड के रूप में जोड़ना होगा, के साथ form.formlabel

# form holder
form_holder = {
    'majeur': {
        'class': FormClass1,
    },
    'majsoft': {
        'class': FormClass2,
    },
    'tiers1': {
        'class': FormClass3,
    },
    'tiers2': {
        'class': FormClass4,
    },
    'tiers3': {
        'class': FormClass5,
    },
    'tiers4': {
        'class': FormClass6,
    },
}

for key in form_holder.keys():
    # If the key is the same as the formlabel, we should use the posted data
    if request.POST.get('formlabel', None) == key:
        # Get the form and initate it with the sent data
        form = form_holder.get(key).get('class')(
            data=request.POST
        )

        # Validate the form
        if form.is_valid():
            # Correct data entries
            messages.info(request, _(u"Configuration validée."))

            if form.save():
                # Save succeeded
                messages.success(
                    request,
                    _(u"Données enregistrées avec succès.")
                )
            else:
                # Save failed
                messages.warning(
                    request,
                    _(u"Un problème est survenu pendant l'enregistrement "
                      u"des données, merci de réessayer plus tard.")
                )
        else:
            # Form is not valid, show feedback to the user
            messages.error(
                request,
                _(u"Merci de corriger les erreurs suivantes.")
            )
    else:
        # Just initiate the form without data
        form = form_holder.get(key).get('class')(key)()

    # Add the attribute for the name
    setattr(form, 'formlabel', key)

    # Append it to the tempalte variable that will hold all the forms
    forms.append(form)

मुझे उम्मीद है कि यह भविष्य में मदद करेगा।


2

यदि आप क्लास-आधारित विचारों और विभिन्न 'एक्शन' अटार्स के साथ दृष्टिकोण का उपयोग कर रहे हैं, तो मेरा मतलब है

दो रूपों के लिए कार्रवाई में अलग-अलग URL डालें। फिर आपके पास दो अलग-अलग रूपों से निपटने के लिए दो अलग-अलग दृश्य कार्य होंगे।

आप ओवरलोड get_context_dataविधि का उपयोग करके विभिन्न रूपों से त्रुटियों को आसानी से संभाल सकते हैं , पूर्व:

views.py:

class LoginView(FormView):
    form_class = AuthFormEdited
    success_url = '/'
    template_name = 'main/index.html'

    def dispatch(self, request, *args, **kwargs):
        return super(LoginView, self).dispatch(request, *args, **kwargs)

    ....

    def get_context_data(self, **kwargs):
        context = super(LoginView, self).get_context_data(**kwargs)
        context['login_view_in_action'] = True
        return context

class SignInView(FormView):
    form_class = SignInForm
    success_url = '/'
    template_name = 'main/index.html'

    def dispatch(self, request, *args, **kwargs):
        return super(SignInView, self).dispatch(request, *args, **kwargs)

    .....

    def get_context_data(self, **kwargs):
        context = super(SignInView, self).get_context_data(**kwargs)
        context['login_view_in_action'] = False
        return context

टेम्पलेट:

<div class="login-form">
<form action="/login/" method="post" role="form">
    {% csrf_token %}
    {% if login_view_in_action %}
        {% for e in form.non_field_errors %}
            <div class="alert alert-danger alert-dismissable">
                {{ e }}
                <a class="panel-close close" data-dismiss="alert">×</a>
            </div>
        {% endfor %}
    {% endif %}
    .....
    </form>
</div>

<div class="signin-form">
<form action="/registration/" method="post" role="form">
    {% csrf_token %}
    {% if not login_view_in_action %}
        {% for e in form.non_field_errors %}
            <div class="alert alert-danger alert-dismissable">
                {{ e }}
                <a class="panel-close close" data-dismiss="alert">×</a>
            </div>
        {% endfor %}
    {% endif %}
   ....
  </form>
</div>

2

राय:

class AddProductView(generic.TemplateView):
template_name = 'manager/add_product.html'

    def get(self, request, *args, **kwargs):
    form = ProductForm(self.request.GET or None, prefix="sch")
    sub_form = ImageForm(self.request.GET or None, prefix="loc")
    context = super(AddProductView, self).get_context_data(**kwargs)
    context['form'] = form
    context['sub_form'] = sub_form
    return self.render_to_response(context)

def post(self, request, *args, **kwargs):
    form = ProductForm(request.POST,  prefix="sch")
    sub_form = ImageForm(request.POST, prefix="loc")
    ...

टेम्पलेट:

{% block container %}
<div class="container">
    <br/>
    <form action="{% url 'manager:add_product' %}" method="post">
        {% csrf_token %}
        {{ form.as_p }}
        {{ sub_form.as_p }}
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
</div>
{% endblock %}

4
क्या आप कृपया अपना उत्तर बता सकते हैं? यह एक सिम्मिलर समस्या से दूसरों की मदद करेगा और आपके या प्रश्नकर्ता कोड को डीबग करने में मदद कर सकता है ...
creyD

0

यहां ऊपर दिए गए तरीके को संभालना आसान है।

Html टेम्प्लेट में हम पोस्ट डालते हैं

<form action="/useradd/addnewroute/" method="post" id="login-form">{% csrf_token %}

<!-- add details of form here-->
<form>
<form action="/useradd/addarea/" method="post" id="login-form">{% csrf_token %}

<!-- add details of form here-->

<form>

दृश्य में

   def addnewroute(request):
      if request.method == "POST":
         # do something



  def addarea(request):
      if request.method == "POST":
         # do something

URL में जैसे आवश्यक जानकारी दें

urlpatterns = patterns('',
url(r'^addnewroute/$', views.addnewroute, name='addnewroute'),
url(r'^addarea/', include('usermodules.urls')),
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.