मैं स्वचालित रूप से अजाक्स का उपयोग करके एक Django फॉर्मेट में नए रूपों को जोड़ना चाहता हूं, ताकि जब उपयोगकर्ता "ऐड" बटन पर क्लिक करे तो यह जावास्क्रिप्ट चलाता है जो पेज पर एक नया फॉर्म (जो कि फॉरमेट का हिस्सा है) जोड़ता है।
मैं स्वचालित रूप से अजाक्स का उपयोग करके एक Django फॉर्मेट में नए रूपों को जोड़ना चाहता हूं, ताकि जब उपयोगकर्ता "ऐड" बटन पर क्लिक करे तो यह जावास्क्रिप्ट चलाता है जो पेज पर एक नया फॉर्म (जो कि फॉरमेट का हिस्सा है) जोड़ता है।
जवाबों:
यह है कि मैं इसे कैसे करता हूं, jQuery का उपयोग करके :
मेरा टेम्प्लेट:
<h3>My Services</h3>
{{ serviceFormset.management_form }}
{% for form in serviceFormset.forms %}
<div class='table'>
<table class='no_error'>
{{ form.as_table }}
</table>
</div>
{% endfor %}
<input type="button" value="Add More" id="add_more">
<script>
$('#add_more').click(function() {
cloneMore('div.table:last', 'service');
});
</script>
एक जावास्क्रिप्ट फ़ाइल में:
function cloneMore(selector, type) {
var newElement = $(selector).clone(true);
var total = $('#id_' + type + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
});
newElement.find('label').each(function() {
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
$(this).attr('for', newFor);
});
total++;
$('#id_' + type + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
यह क्या करता है:
cloneMore
selector
पहले तर्क के रूप में, और type
दूसरे के रूप में फॉर्मेट को स्वीकार करता है । क्या करना selector
चाहिए इसे पास करें जो इसे डुप्लिकेट करना चाहिए। इस मामले में, मैं इसे पास करता हूं div.table:last
ताकि jQuery वर्ग के साथ अंतिम तालिका के लिए दिखे table
। इसका :last
हिस्सा महत्वपूर्ण है क्योंकि इसका selector
उपयोग यह निर्धारित करने के लिए भी किया जाता है कि बाद में नया रूप क्या डाला जाएगा। बाकी रूपों के अंत में आप इसे अधिक से अधिक चाहेंगे। type
तर्क ताकि हम अद्यतन कर सकते हैं है management_form
क्षेत्र, विशेष रूप से TOTAL_FORMS
, साथ ही वास्तविक प्रपत्र फ़ील्ड्स। यदि आपके पास एक फ़ॉर्मेट है, तो कहें, Client
मॉडल, प्रबंधन फ़ील्ड की आईडी id_clients-TOTAL_FORMS
और id_clients-INITIAL_FORMS
, जबकि फॉर्म फ़ील्ड के id_clients-N-fieldname
साथ एक प्रारूप में होगाN
फॉर्म नंबर होने के साथ, शुरू करना 0
। तो साथ type
तर्क cloneMore
कितने रूपों में समारोह दिखता है वहाँ वर्तमान में कर रहे हैं, और हर इनपुट और की तरह कुछ से सभी फ़ील्ड नाम / आईडी की जगह नए रूप के अंदर लेबल के माध्यम से चला जाता है id_clients-(N)-name
के लिए id_clients-(N+1)-name
और इतने पर। समाप्त होने के बाद, यह TOTAL_FORMS
नए फॉर्म को प्रतिबिंबित करने के लिए फ़ील्ड को अपडेट करता है और इसे सेट के अंत में जोड़ता है।
यह फ़ंक्शन मेरे लिए विशेष रूप से उपयोगी है क्योंकि जिस तरह से यह सेटअप है, यह मुझे पूरे ऐप में इसका उपयोग करने की अनुमति देता है जब मैं एक फॉर्मसेट में अधिक रूप प्रदान करना चाहता हूं, और मुझे नकल करने के लिए छिपे हुए "टेम्पलेट" फॉर्म की आवश्यकता नहीं है जब तक मैं इसे फॉर्मेट नाम और प्रारूप को पास करता हूं, जब तक कि फॉर्म जमा नहीं हो जाते। आशा करता हूँ की ये काम करेगा।
prefix
फॉर्मसेट ऑब्जेक्ट के सदस्य को एक मूल्य निर्दिष्ट करने की आवश्यकता होगी । यह फ़ंक्शन के type
लिए तर्क के समान मूल्य होना चाहिए cloneMore
।
empty_form
टेम्पलेट के रूप में पाओलो के उत्तर का सरलीकृत संस्करण ।
<h3>My Services</h3>
{{ serviceFormset.management_form }}
<div id="form_set">
{% for form in serviceFormset.forms %}
<table class='no_error'>
{{ form.as_table }}
</table>
{% endfor %}
</div>
<input type="button" value="Add More" id="add_more">
<div id="empty_form" style="display:none">
<table class='no_error'>
{{ serviceFormset.empty_form.as_table }}
</table>
</div>
<script>
$('#add_more').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
CompetitorFormSet = modelformset_factory(ProjectCompetitor, formset=CompetitorFormSets)
ctx['competitor_form_set'] = CompetitorFormSet(request.POST)
हूं तो मुझे केवल एक ही रूप मिलता है, स्वच्छ विधि में। क्या आप कृपया बता सकते हैं कि विचारों में यह कैसे निपटाएँ?
empty_form
) का उत्कृष्ट उपयोग करता है , जिसकी मैं सराहना करता हूं।
मैंने एक ऐप से स्निपेट पोस्ट किया है जिसे मैंने कुछ समय पहले काम किया था। पाओलो के समान है, लेकिन आपको फ़ॉर्म हटाने की भी अनुमति देता है।
पाओलो का सुझाव एक कैविएट के साथ खूबसूरती से काम करता है - ब्राउजर के बैक / फॉरवर्ड बटन।
पाओलो की स्क्रिप्ट के साथ बनाए गए गतिशील तत्वों का प्रतिपादन नहीं किया जाएगा यदि उपयोगकर्ता बैकडेट / फॉरवर्ड बटन का उपयोग करके फॉर्मेट पर वापस लौटता है। एक मुद्दा जो कुछ के लिए एक सौदा ब्रेकर हो सकता है।
उदाहरण:
1) उपयोगकर्ता "ऐड-मोर" बटन का उपयोग करके फॉर्मेट में दो नए फॉर्म जोड़ता है
2) उपयोगकर्ता रूपों को पॉप्युलेट करता है और फॉर्मेट को सबमिट करता है
3) उपयोगकर्ता ब्राउज़र में बैक बटन पर क्लिक करता है
4) फॉर्मसेट अब मूल रूप में कम हो गया है, सभी गतिशील रूप से जोड़े गए फॉर्म नहीं हैं
यह पाओलो की पटकथा के साथ एक दोष नहीं है; लेकिन डोम हेरफेर और ब्राउज़र के कैश के साथ जीवन का एक तथ्य।
मुझे लगता है कि एक सत्र में फॉर्म के मूल्यों को संग्रहीत कर सकता है और कुछ अजाक्स जादू है जब फॉर्मेट फिर से तत्वों को बनाने और सत्र से मूल्यों को फिर से लोड करने के लिए लोड करता है; लेकिन एक ही उपयोगकर्ता और फार्म के कई उदाहरणों के बारे में आप कितना गुदा होना चाहते हैं, इस पर निर्भर करता है कि यह बहुत जटिल हो सकता है।
किसी को भी इससे निपटने के लिए एक अच्छा सुझाव है?
धन्यवाद!
डायनामोजिक रूपों के लिए निम्नलिखित समाधान देखें:
http://code.google.com/p/django-dynamic-formset/
https://github.com/javisantana/django-dinamyc-form/tree/master/frm
वे दोनों jQuery का उपयोग करते हैं और django- विशिष्ट हैं। पहले थोड़ा अधिक पॉलिश लगता है और एक डाउनलोड प्रदान करता है जो w / डेमो आता है जो उत्कृष्ट हैं।
अनुकरण और अनुकरण करें:
<input>
फ़ील्ड पर ध्यान दें ।<input>
फ़ील्ड कैसे बदले, इस पर ध्यान दें ।जब मुझे पता है कि फॉर्मेट्स विशेष छिपे हुए <input>
फ़ील्ड का उपयोग करते हैं और लगभग जानते हैं कि स्क्रिप्ट को क्या करना चाहिए, तो मुझे अपने सिर के ऊपर से विवरण याद नहीं है। मैंने ऊपर जो वर्णन किया है, वह मैं आपकी स्थिति में करूँगा।
इसके लिए एक jquery प्लगइन है , मैंने इसे Django 1.3 में इनलाइन_फॉर्म सेट के साथ उपयोग किया था, और यह पूरी तरह से काम करता है, जिसमें प्रीपोपुलेशन, क्लाइंट साइड फॉर्म जोड़ना, निकालना और कई इनलाइन_फॉर्म शामिल हैं।
एक विकल्प यह होगा कि हर संभव फॉर्म के साथ एक फॉर्मेट बनाया जाए, लेकिन शुरू में अप्रतिबंधित फॉर्म को छिपाए - यानी display: none;
। जब किसी फॉर्म को प्रदर्शित करना आवश्यक होता है, तो यह css प्रदर्शन block
या जो भी उपयुक्त हो, सेट करें ।
आपके "अजाक्स" क्या कर रहा है, इसके बारे में अधिक जानकारी के बिना, अधिक विस्तृत प्रतिक्रिया देना कठिन है।
एक और क्लोनमोर संस्करण, जो खेतों के चयनात्मक संजीवनीकरण की अनुमति देता है। जब आपको कई क्षेत्रों को मिटाने से रोकने की आवश्यकता हो तो इसका उपयोग करें।
$('table tr.add-row a').click(function() {
toSanitize = new Array('id', 'product', 'price', 'type', 'valid_from', 'valid_until');
cloneMore('div.formtable table tr.form-row:last', 'form', toSanitize);
});
function cloneMore(selector, type, sanitize) {
var newElement = $(selector).clone(true);
var total = $('#id_' + type + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var namePure = $(this).attr('name').replace(type + '-' + (total-1) + '-', '');
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).removeAttr('checked');
if ($.inArray(namePure, sanitize) != -1) {
$(this).val('');
}
});
newElement.find('label').each(function() {
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
$(this).attr('for', newFor);
});
total++;
$('#id_' + type + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
क्लोनमोर फ़ंक्शन के साथ एक छोटा मुद्दा है। चूँकि यह django ऑटो जनरेट किए गए छिपे हुए फ़ील्ड के मूल्य को भी साफ कर रहा है, यह django को शिकायत करता है यदि आप एक से अधिक खाली फॉर्म वाले फॉर्मेट को सहेजने का प्रयास करते हैं।
यहाँ एक तय है:
function cloneMore(selector, type) {
var newElement = $(selector).clone(true);
var total = $('#id_' + type + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
var id = 'id_' + name;
if ($(this).attr('type') != 'hidden') {
$(this).val('');
}
$(this).attr({'name': name, 'id': id}).removeAttr('checked');
});
newElement.find('label').each(function() {
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
$(this).attr('for', newFor);
});
total++;
$('#id_' + type + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
मुझे लगता है कि यह एक बेहतर समाधान है।
आप Django में एक गतिशील फॉर्मेट कैसे बनाएंगे?
क्या चीजें क्लोन नहीं करती हैं:
कोडर्स के लिए, जो उपरोक्त समाधानों को थोड़ा बेहतर समझने के लिए शिकार के संसाधन हैं:
उपरोक्त लिंक को पढ़ने के बाद, Django प्रलेखन और पिछले समाधानों को बहुत अधिक अर्थ देना चाहिए।
एक त्वरित सारांश के रूप में मैं क्या उलझन में था: प्रबंधन प्रपत्र में रूपों का अवलोकन शामिल है। Django को आपके द्वारा जोड़े जाने वाले प्रपत्रों के बारे में जानने के लिए आपको उस जानकारी को सही रखना होगा। (समुदाय, कृपया मुझे सुझाव दें अगर मेरी कुछ शब्दावली यहाँ से हट गई है। Im Django के लिए नया है।)
@ पाओलो बर्गेंटिनो
क्लोन करने के लिए संलग्न सभी हैंडलर बस लाइन को संशोधित करते हैं
var newElement = $(selector).clone();
के लिये
var newElement = $(selector).clone(true);
हाँ, मैं भी आपको उन्हें html में प्रस्तुत करने की सलाह दूंगा यदि आपके पास प्रविष्टियों की एक सीमित संख्या है। (यदि आप ऐसा नहीं करते हैं तो आपको दूसरी विधि का उपयोग करना होगा)।
आप उन्हें इस तरह छिपा सकते हैं:
{% for form in spokenLanguageFormset %}
<fieldset class="languages-{{forloop.counter0 }} {% if spokenLanguageFormset.initial_forms|length < forloop.counter and forloop.counter != 1 %}hidden-form{% endif %}">
तब js वास्तव में सरल है:
addItem: function(e){
e.preventDefault();
var maxForms = parseInt($(this).closest("fieldset").find("[name*='MAX_NUM_FORMS']").val(), 10);
var initialForms = parseInt($(this).closest("fieldset").find("[name*='INITIAL_FORMS']").val(), 10);
// check if we can add
if (initialForms < maxForms) {
$(this).closest("fieldset").find("fieldset:hidden").first().show();
if ($(this).closest("fieldset").find("fieldset:visible").length == maxForms ){
// here I'm just hiding my 'add' link
$(this).closest(".control-group").hide();
};
};
}
क्योंकि उपरोक्त सभी उत्तर jQuery का उपयोग करते हैं और कुछ चीजों को थोड़ा जटिल बनाते हैं जिन्हें मैंने निम्नलिखित स्क्रिप्ट में लिखा था:
function $(selector, element) {
if (!element) {
element = document
}
return element.querySelector(selector)
}
function $$(selector, element) {
if (!element) {
element = document
}
return element.querySelectorAll(selector)
}
function hasReachedMaxNum(type, form) {
var total = parseInt(form.elements[type + "-TOTAL_FORMS"].value);
var max = parseInt(form.elements[type + "-MAX_NUM_FORMS"].value);
return total >= max
}
function cloneMore(element, type, form) {
var totalElement = form.elements[type + "-TOTAL_FORMS"];
total = parseInt(totalElement.value);
newElement = element.cloneNode(true);
for (var input of $$("input", newElement)) {
input.name = input.name.replace("-" + (total - 1) + "-", "-" + total + "-");
input.value = null
}
total++;
element.parentNode.insertBefore(newElement, element.nextSibling);
totalElement.value = total;
return newElement
}
var addChoiceButton = $("#add-choice");
addChoiceButton.onclick = function() {
var choices = $("#choices");
var createForm = $("#create");
cloneMore(choices.lastElementChild, "choice_set", createForm);
if (hasReachedMaxNum("choice_set", createForm)) {
this.disabled = true
}
};
पहले आपको auto_id को गलत पर सेट करना चाहिए और इसलिए आईडी और नाम के दोहराव को अक्षम करना चाहिए । क्योंकि इनपुट नामों को वहाँ के रूप में अद्वितीय होना चाहिए, सभी पहचान उनके साथ की जाती है न कि आईडी के साथ। तुम भी बदलने के लिए form
, type
और formset के कंटेनर। (उपरोक्त उदाहरण में choices
)