前提・実現したいこと
Djangoのformsetを動的に追加したい
[1] Choiceモデルをformsetで最低2つ、最高5つまで追加できるようにしています。
[2] view.py内で、作成したChoiceモデルをQuestionモデルに紐づけています。
[3] JavaScriptでformの追加ボタン、削除ボタンを設置しています。
できていること
・追加・削除ボタンは正しく動作し、それぞれのformのidも正しく設定されています。
・min_numで設定した最初の2つのChoiceモデルは正しく追加されます
発生している問題
35つ目までのChoiceモデルがQuestionに追加されない。5つ目までの各formがformsetそのものに追加されていないらしい。
どうやら3
ということで、追加ボタンで作成したformをformsetに追加するにはどうしたらいいですか?
該当のソースコード
Python
1"""model.py""" 2class Question(models.Model): 3 #省略 4 5class Choice(models.Model): 6 number = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(5)], default=0) 7 question = models.ForeignKey(Question, on_delete=models.CASCADE) 8 choice_text = models.CharField("選択肢", max_length=100) 9 votes = models.IntegerField(default=0) 10 11 def __str__(self): 12 return self.choice_text 13 14"""form.py""" 15class QuestionForm(forms.ModelForm): 16 #省略 17 18class ChoiceForm(forms.ModelForm): 19 class Meta: 20 model = Choice 21 fields = ("choice_text",) 22 widgets = { 23 "choice_text" : forms.Textarea(attrs={"cols": 10, "rows": 2, "placeholder": "100字まで"}), 24 } 25 labels = { 26 "choice_text": "" 27 } 28 29ChoiceFormSet = forms.formset_factory(ChoiceForm, extra=0, min_num=2, max_num=5) 30 31"""view.py""" 32def question_create(request): 33 form = QuestionForm(request.POST) 34 formset = ChoiceFormSet(request.POST) 35 if form.is_valid() and formset.is_valid(): 36 question = form.save(commit=False) 37 38 num = 0 39 for field in formset: 40 question.choice_set.create( 41 number=num, 42 choice_text=field.cleaned_data["choice_text"], 43 votes=0 44 ) 45 num += 1 46 question.save() 47 return redirect("polls:create_complete", pk=question.id) 48 49 else: 50 form = QuestionForm() 51 formset = ChoiceFormSet() 52 53 question.save() 54 55 return redirect("polls:create_complete", pk=question.id)
html
1{% block content %} 2<form action="" method="POST"> 3 <div class="form-group row"> 4 <div class="col-sm-6"> 5 {{ form|crispy }} 6 {{ form.error }} 7 </div> 8 <div class="col-sm-6"> 9 <label>選択肢*</label> 10 <div id="choice-area"> 11 {{ formset.management_form }} 12 {% for form2 in formset %} 13 <div id="choice-form-{{ forloop.counter0 }}"> 14 {{ form2|crispy }} 15 </div> 16 {% endfor %} 17 </div> 18 <button id="add" type="button" class="btn btn-outline-success">選択肢を追加</button> 19 <button id="remove" type="button" class="btn btn-outline-secondary">選択肢を削除</button> 20 {% csrf_token %} 21 </form> 22{% endblock %} 23 24{% block js %} 25<script type="text/html" id="choiceCreate-template"> 26 <div id="choice-form-__prefix__"> 27 {{ form2|crispy }} 28 </div> 29</script> 30 31<script> 32$(function(){ 33 var totalManageElement = $('#id_form-TOTAL_FORMS'); 34 var currentChoiceCount = parseInt(totalManageElement.val()); 35 var tmpMarkup = $('#choiceCreate-template').html(); 36 currentChoiceCount -= 1; 37 38 $('button#add').on('click', function(){ 39 if ( currentChoiceCount == 4 ) { return; } 40 currentChoiceCount += 1; 41 var compiledTmp = tmpMarkup.replace(/__prefix__/g, currentChoiceCount); 42 $('div#choice-area').append(compiledTmp); 43 totalManageElement.attr('value', currentChoiceCount); 44 }); 45 46 $('button#remove').on('click', function(){ 47 if ( currentChoiceCount == 1 ) { return; } 48 $('#choice-form-' + currentChoiceCount).remove(); 49 currentChoiceCount -= 1; 50 totalManageElement.attr('value', currentChoiceCount); 51 }); 52}); 53</script> 54{% endblock %}
補足情報(FW/ツールのバージョンなど)
Django3.0.4
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。