質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

2691閲覧

【Django】追加ボタンで生成したformがformsetに追加されない

退会済みユーザー

退会済みユーザー

総合スコア0

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2020/05/20 00:34

前提・実現したいこと

Djangoのformsetを動的に追加したい

[1] Choiceモデルをformsetで最低2つ、最高5つまで追加できるようにしています。
[2] view.py内で、作成したChoiceモデルをQuestionモデルに紐づけています。
[3] JavaScriptでformの追加ボタン、削除ボタンを設置しています。

できていること

・追加・削除ボタンは正しく動作し、それぞれのformのidも正しく設定されています。
・min_numで設定した最初の2つのChoiceモデルは正しく追加されます

発生している問題

35つ目までのChoiceモデルがQuestionに追加されない。
どうやら3
5つ目までの各formがformsetそのものに追加されていないらしい。

ということで、追加ボタンで作成した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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

解決しました。
2つ変更する点があります。
1つ目が、formset.management_formをdiv#choice_areaの外に出すこと。外に出すと、テンプレートで追加したformも追加されました。
2つ目が、scriptタグ内で、totalManageElement.attr('value', currentChoiceCount + 1);とすること。これは、番号を0,1,2…と振っているため、TOTAL_FORMの数自体は最後の要素の添字+1になるからです。

投稿2020/05/21 03:01

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問