サブフォーム側に複数レコードがあり、なおかつ複数サブフォームを使う必要があり、はじめはインラインフォームをつかってできないかとおもいやっていたのですが、登録はともかく、更新などがうまくいきませんでした。そこでしらべたところ、ほぼそのままなんですが、こちらの記事を参考にしたところ、(ありがとうございます m(__)m) django-extra-viewsを使うことで凡そのことができたので、備忘録として挙げてみました。
まず、django-extra-viewsをインストールします。debianではpython3-django-extra-viewsパッケージがあるので、これをインストールしておきます。
つづいてviews.pyとforms.pyですが以下の様にしました。
今回は以上です。それでは。
まず、django-extra-viewsをインストールします。debianではpython3-django-extra-viewsパッケージがあるので、これをインストールしておきます。
つづいてviews.pyとforms.pyですが以下の様にしました。
#views.py class artCreateView(CreateWithInlinesView): model = art fields = ('art_name', 'cat1', 'cat2', 'cat3', 'cat4', 'url1', 'url2',) context_object_name = 'art' inlines = [art_propForm] template_name = 'myapp/edit.html' success_url = reverse_lazy('pc:top') factory_kwargs = { 'can_order': True, 'can_delete': True} class artUpdateView(UpdateWithInlinesView): model = art form_class = artForm inlines = [art_propForm] template_name = 'myapp/edit.html' success_url = reverse_lazy('pc:top') factory_kwargs = { 'can_order': True, 'can_delete': True}
#forms.py from django import forms from extra_views.advanced import InlineFormSetFactory from .models import art, art_prop class artForm(forms.ModelForm): class Meta: model = art fields = ('art_name', 'cat1', 'cat2', 'cat3', 'cat4', 'url1', 'url2',) def save(self, commit=True): instance = super(artForm, self).save(commit=commit) if commit: instance.save() return instance class art_propForm(InlineFormSetFactory): model = art_prop fields = '__all__'viewsとformsで基本的に必要な記述は一サブフォームの場合これだけです。非常にシンプルですね。models.pyは割愛しますが、つづいてurls.pyとテンプレートは以下のようにしました。
from django.urls import path, include from . import views app_name = 'myapp' urlpatterns = [ path('create/', views.artCreateView.as_view(), name='create'), path('update/<int:pk>/', views.artUpdateView.as_view(), name='update'), ]
{% extends 'base/base.html' %} {% load static%} {% block content %} <form action="." method="post"> {% csrf_token %} <p>article</p> <table> {{ form.as_table }} </table> {% for formset in inlines %} {{ formset.prefix }} <p>子テーブル(child{{forloop.counter}})</p> <table id="formset{{forloop.counter}}" class="table table-sm "> {{ formset.management_form }} {% for form in formset %} <!-- ヘッダ出力 --> {% ifequal forloop.counter0 0 %} {% for field in form %} <td class="bg-light"> {% if field.field.widget.is_hidden %} {% else %} {{ field.label_tag }} {% endif %} </td> {% endfor %} {% endifequal %} <tr> {% for field in form %} <td> {{ field }} </td> {% endfor %} </tr> {% endfor %} </table> <button id="add{{forloop.counter}}" type="button" class="ui standard button">add1</button> <button id="del{{forloop.counter}}" type="button" class="ui standard button">del1</button> {% endfor %} <br/> <br/> <input class="ui standard button" type="submit" value="登録" /> {% endblock content %} {% block extrajs %} <script> $('#add1').click(function() { var prop = $("#formset1 tr:last-child") var formCount = $('#id_art_prop_set-TOTAL_FORMS').val(); clone = prop.clone().insertAfter(prop); // clone.children().not(':last').children().each(function(idx,elm){ clone.children().children().each(function(idx,elm){ console.log("add1: before updating..."); updateElementIndex(this,'art_prop_set', formCount); $(this).val(''); $(this).prop('checked', false) }); $('#id_art_prop_set-TOTAL_FORMS').val(++formCount); }); $('#del1').on('click', function(){ var prop = $('#formset1 tr'); var line = $('#id_art_prop_set-TOTAL_FORMS').val(); var i = 0; var j = line; prop.each(function(IDX, ELM){ if ($(ELM).find('input[type="checkbox"]').prop('checked')){ i++; //console.log("i is : ", i); //console.log("DELETE is checkd: ", IDX); if (line == 1 || line == i ){ $(ELM).find("input").val(''); $(ELM).find("input:checkbox").prop('checked', false); j=1; } else { $(ELM).hide(); j = j -1; } } else { //console.log("DELET is not checkd. ", IDX); } // $('#id_art_prop_set-TOTAL_FORMS').val(j); }); prop = $("#formset1 tr") console.log('prop.length', prop.length); for (var i=0, formCount = prop.length; i < formCount; ++i) { // $(prop.get(i)).children().not(':last').children().each(function() { $(prop.get(i)).find('input').not('label').each(function() { console.log('i - 1: ', i - 1); if (i == 0){ console.log('do nothing ...') } else { // updateElementIndex(this, 'art_prop_set', i - 1); } }); } }); function updateElementIndex(el, prefix, ndx) { var id_regex = new RegExp('(' + prefix + '-\\d+)'); var replacement = prefix + '-' + ndx; if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement)); if (el.id) el.id = el.id.replace(id_regex, replacement); if (el.name) el.name = el.name.replace(id_regex, replacement); }; $('#add2').click(function() { }); $('#del2').click(function() { }) </script> {% endblock %}テンプレートは、javascriptの部分がごちゃごちゃしていて汚いのですが、とりあえず以上の様にしました。サブフォームを展開するときに、id=formset{{forloop.counter}}としてあるので、追加・削除(実際には非表示化で更新時に削除)ボタンをクリックしたときに、目的のサブフォーム列を操作できるようにjavascript側で識別して動作できるようにできました。このあと画像の登録も追加する予定なのですが、コードの記述量が非常にすくなくて済みそうです。
今回は以上です。それでは。
コメント
コメントを投稿