양식에 동적으로 필드 추가
내 양식에 3 개의 필드가 있습니다. 제출 버튼과 "추가 필드 추가"버튼이 있습니다. __init__
양식 클래스의 메서드를 사용하여 필드를 추가 할 수 있음을 이해 합니다.
저는 Python과 Django를 처음 사용하고 초보자 질문에 갇혀 있습니다. 제 질문은 다음과 같습니다.
"추가 필드 추가"버튼을 클릭하면 추가 필드를 추가하는 과정은 무엇입니까?
양식을 다시 렌더링해야합니까?
언제 어떻게 __init__
전화를하나요? 아니면 전화를해야하나요?
인수를 __init__
어떻게 전달 합니까?
양식은 POST에서 전달 된 일부 변수를 기반으로 구성되어야합니다 (또는 속성을 맹목적으로 확인). 양식 자체는 오류 여부에 관계없이 뷰가 다시로드 될 때마다 구성되므로 HTML은 유효성 검사를 위해 올바른 양의 필드를 구성하기 위해 얼마나 많은 필드가 있는지에 대한 정보를 포함해야합니다.
이 문제를 FormSet
작동 방식으로 살펴 보겠습니다 . 활성 양식 수를 포함하는 숨겨진 필드가 있고 각 양식 이름 앞에 양식 색인이 추가됩니다.
사실 하나의 필드를 만들 수 있습니다. FormSet
https://docs.djangoproject.com/en/dev/topics/forms/formsets/#formsets
를 사용하지 않으려면 FormSet
언제든지이 동작을 직접 만들 수 있습니다.
여기 처음부터 만든 것이 있습니다. 그것은 당신에게 몇 가지 아이디어를 줄 것입니다. 또한 인수 전달에 대한 질문에 대답합니다 __init__
. 객체 생성자에 인수를 전달하기 만하면됩니다.MyForm('arg1', 'arg2', kwarg1='keyword arg')
양식
class MyForm(forms.Form):
original_field = forms.CharField()
extra_field_count = forms.CharField(widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('extra', 0)
super(MyForm, self).__init__(*args, **kwargs)
self.fields['extra_field_count'].initial = extra_fields
for index in range(int(extra_fields)):
# generate extra fields in the number specified via extra_fields
self.fields['extra_field_{index}'.format(index=index)] = \
forms.CharField()
전망
def myview(request):
if request.method == 'POST':
form = MyForm(request.POST, extra=request.POST.get('extra_field_count'))
if form.is_valid():
print "valid!"
else:
form = MyForm()
return render(request, "template", { 'form': form })
HTML
<form>
<div id="forms">
{{ form.as_p }}
</div>
<button id="add-another">add another</button>
<input type="submit" />
</form>
JS
<script>
form_count = Number($("[name=extra_field_count]").val());
// get extra form count so we know what index to use for the next item.
$("#add-another").click(function() {
form_count ++;
element = $('<input type="text"/>');
element.attr('name', 'extra_field_' + form_count);
$("#forms").append(element);
// build element and append it to our forms container
$("[name=extra_field_count]").val(form_count);
// increment form count so our view knows to populate
// that many fields for validation
})
</script>
동적 필드를 사용하여 양식을 동적으로 만들어야하는 경우가 있습니다. 이 트릭으로 한 것 :
from django import forms
...
dyn_form = type('DynForm', # form name is irrelevant
(forms.BaseForm,),
{'base_fields': fields})
자세한 정보는이 링크를 참조하십시오 : 동적 양식
그러나 그 외에도 필드를 삽입해야했습니다. 즉, 생성 된 양식 클래스에 동적으로 필드를 추가해야했습니다.
dyn_form.base_fields['field1'] = forms.IntegerField(widget=forms.HiddenInput(), initial=field1_val)
dyn_form.base_fields['field2'] = forms.CharField(widget=forms.HiddenInput(), initial=field2_val)
그리고 그것은 효과가있었습니다.
자바 스크립트와 필드 유형이없는 방법은 js에서 설명되지 않습니다.
파이썬
def __init__(self, *args, **kwargs):
super(Form, self).__init__(*args, **kwargs)
##ajouts des champs pour chaque chien
for index in range(int(nb_dogs)):
self.fields.update({
'dog_%s_name' % index: forms.CharField(label=_('Name'), required=False, max_length=512),
})
def fields_dogs(self):
fields = []
for index in range(int(nb_dogs)):
fields.append({
'name': self['dog_%s_name' % index],
})
return fields
주형
{% for field_dog in f.fields_dogs %}
<thead>
<tr>
<th style="background-color: #fff; border-width: 0px;"></th>
<th>{% trans 'Dog' %} #{{forloop.counter}}</th>
<th>{% trans 'Name' %}</th>
</tr>
</thead>
<tbody>
<tr>
<td style="background-color: #fff; border-width: 0px;"></td>
<td style="background-color: #fff; border-width: 0px;"></td>
<td>{{field_dog.name.errors}}{{field_dog.name}}</td>
</tr>
<tr>
<td style="padding: 10px; border-width: 0px;"></td>
</tr>
</tbody>
{% endfor %}
이 답변은 @ Yuji'Tomita'Tomita의 몇 가지 개선 사항과 변경 사항을 기반으로합니다.
@ Yuji'Tomita'Tomita 답변이 훌륭하고 "장고 양식에 추가 필드 추가"기능을 빌드하기 위해 따라야 할 방향을 멋지고 간단하게 설명하지만 코드의 일부에 문제가 있음을 발견했습니다.
여기에 @ Yuji'Tomita'Tomita의 초기 제안에 따라 작업 코드를 제공합니다.
보기 (view.py 파일에서)
보기에서 실제로 변경되는 것은 없습니다.
def myview(request):
if request.method == 'POST':
form = MyForm(request.POST, extra=request.POST.get('total_input_fields'))
if form.is_valid():
print "valid!"
else:
form = MyForm()
return render(request, "template", { 'form': form })
양식 (form.py 파일에 있음)
class MyForm(forms.Form):
empty_layer_name = forms.CharField(max_length=255, required=True, label="Name of new Layer")
total_input_fields = forms.CharField(widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('extra', 0)
# check if extra_fields exist. If they don't exist assign 0 to them
if not extra_fields:
extra_fields = 0
super(MyForm, self).__init__(*args, **kwargs)
self.fields['total_input_fields'].initial = extra_fields
for index in range(int(extra_fields)):
# generate extra fields in the number specified via extra_fields
self.fields['extra_field_{index}'.format(index=index)] = forms.CharField()
템플릿 HTML
<form id="empty-layer-uploader" method="post" enctype="multipart/form-data" action="{% url "layer_create" %}">
<div id="form_empty_layer">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
{{ form.errors }}
{{ form.non_field_errors }}
{% if errormsgs %}
{% for value in errormsgs %}
</p> {{ value }} </p>
{% endfor %}
{% endif %}
{% for error in form_empty_layer.non_field_errors %}
{{ error }} </br>
{% endfor %}
</br>
{% for field in form_empty_layer.visible_fields %}
{{ field }} </br>
{% endfor %}
</div>
</br>
<button type="button" id="add-another">add another</button> </br> </br>
<button type="submit" id="empty-layer-button" name="emptylayerbtn">Upload</button>
</br></br>
// used in order to save the number of added fields (this number will pass to forms.py through the view)
<input type="text" name="total_input_fields"/>
</form>
템플릿 Jquery
// check how many times elements with this name attribute exist: extra_field_*
form_count = $('input[name*="extra_field_*"]').length;
// when the button 'add another' is clicked then create a new input element
$(document.body).on("click", "#add-another",function(e) {
new_attribute = $('<input type="text"/>');
// add a name attribute with a corresponding number (form_count)
new_attribute.attr('name', 'extra_field_' + form_count);
// append the new element in your html
$("#form_empty_layer").append(new_attribute);
// increment the form_count variable
form_count ++;
// save the form_count to another input element (you can set this to invisible. This is what you will pass to the form in order to create the django form fields
$("[name=total_input_fields]").val(form_count);
})
Yuji 'Tomita'Tomita의 솔루션은 당신이 찾을 수있는 최고의 솔루션이지만, 여러 단계의 양식이 있고 django-formtools 앱을 사용한다고 가정하면 몇 가지 문제를 해결해야 할 것입니다. Yuji 'Tomita'Tomita 감사합니다. 많이 도와 주셨습니다. :)
forms.py
class LicmodelForm1(forms.Form):
othercolumsvalue = forms.IntegerField(min_value=0, initial=0)
class LicmodelForm2(forms.Form):
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('extra', 0)
super(LicmodelForm2, self).__init__(*args, **kwargs)
for index in range(int(extra_fields)):
# generate extra fields in the number specified via extra_fields
self.fields['othercolums_{index}'.format(index=index)] = \
forms.CharField()
self.fields['othercolums_{index}_nullable'.format(index=index)] = \
forms.BooleanField(required=False)
For a multiple-step form, you will not need the extra field, in this code we use othercolumsvalue field in the first-step.
views.py
class MyFormTool(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def get_context_data(self, form, **kwargs):
context = super(MyFormTool, self).get_context_data(form=form, **kwargs)
data_step1 = self.get_cleaned_data_for_step('step1')
if self.steps.current == 'step2':
#prepare tableparts for the needLists
needList_counter = 0
for i in self.wellKnownColums:
if data_step1[i] is True:
needList_counter = needList_counter + 1
pass
#prepare tableparts for othercolums
othercolums_count = []
for i in range(0, data_step1['othercolumsvalue']):
othercolums_count.append(str(i))
context.update({'step1': data_step1})
context.update({'othercolums_count': othercolums_count})
return context
def get_form(self, step=None, data=None, files=None):
form = super(MyFormTool, self).get_form(step, data, files)
if step is None:
step = self.steps.current
if step == 'step2':
data = self.get_cleaned_data_for_step('step1')
if data['othercolumsvalue'] is not 0:
form = LicmodelForm2(self.request.POST,
extra=data['othercolumsvalue'])
return form
def done(self, form_list, **kwargs):
print('done')
return render(self.request, 'formtools_done.html', {
'form_data' : [form.cleaned_data for form in form_list],
})
By overriding the get_form() and get_context_data() functions you can override the form befor it gets rendered. You will not need JavaScript anymore either for your template-file:
{% if step1.othercolumsvalue > 0 %}
<tr>
<th>Checkbox</th>
<th>Columname</th>
</tr>
{% for i in othercolums_count %}
<tr>
<td><center><input type="checkbox" name="othercolums_{{ i }}_nullable" id="id_othercolums_{{ i }}_nullable" /></center></td>
<td><center><input type="text" name="othercolums_{{ i }}" required id="id_othercolums_{{ i }}" /></center></td>
</tr>
{% endfor %}
{% endif %}
The fields from step2 the were made dynamically were also reconized from the formtools because of the same name. But to get there you will have to work around the for-each template loops as you can see:
from the get_context_data()-function
othercolums_count = []
for i in range(0, data_step1['othercolumsvalue']):
othercolums_count.append(str(i))
ReferenceURL : https://stackoverflow.com/questions/6142025/dynamically-add-field-to-a-form
'program tip' 카테고리의 다른 글
grep에서 괄호를 이스케이프하는 방법 (0) | 2021.01.08 |
---|---|
멱등 함수는 순수 함수와 동일합니까? (0) | 2021.01.08 |
C에서 0에 대한 포인터 역 참조 (0) | 2021.01.08 |
프로세스 ID로 프로세스 이름 찾기 (0) | 2021.01.08 |
IOHIDFamily의 미스터리 콘솔 오류 (0) | 2021.01.08 |