サブフォーム側に複数レコードがあり、なおかつ複数サブフォームを使う必要があり、はじめはインラインフォームをつかってできないかとおもいやっていたのですが、登録はともかく、更新などがうまくいきませんでした。そこでしらべたところ、ほぼそのままなんですが、こちらの記事を参考にしたところ、(ありがとうございます 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側で識別して動作できるようにできました。このあと画像の登録も追加する予定なのですが、コードの記述量が非常にすくなくて済みそうです。今回は以上です。それでは。
コメント
コメントを投稿