前提・実現したいこと
一度登録したレコードを編集する画面において、編集した内容がDBに反映されるようにしたいです。
発生している問題・エラーメッセージ
まず最初にCreate
部分の画面になります。この画面で作成したレコードはきちんとDBに反映されます。
次に、Update
部分の画面になります。
この場合は、旅行作成画面で入力した状態のまま変更を加えず、送信した場合になるのですが、
太陽
などが消えて、空白の状態になってしまいます。
次は、新しくフォームを追加した状態になります。
以下がPOST
送信した時の状態になります。
この場合は、地球
などが消えてしまい、空白
になります。
さらに、費用を追加
を押してないのに、費用を追加
するフォームが追加されてしまいます。
また、補足としましては、Create
画面にて入力したレコードがUpdate
画面の初期値として、入力されているものとします。
該当のソースコード
forms.py
文字数の関係で、forms.py
は画像にさせていただきました。
今回はSpot
, Transport
, Other
にて問題が起きていると思いますので、この3つのみを載せておきたいと思います。
views.py
django
1def edit(request, num): 2 other_model = Other.objects.filter(trip=trip_model.id) 3 spot_model = Spot.objects.filter(trip=trip_model) 4 spot_first_model = Spot.objects.filter(trip=trip_model).first() 5 transport_model = Transport.objects.filter(spot__in=spot_model) 6 7 OtherFormSet = forms.modelformset_factory( 8 Other, form=OtherForm, extra=0 9 ) 10 SpotFormSet = forms.modelformset_factory( 11 Spot, form=SpotForm, extra=0 12 ) 13 TransportFormSet = forms.modelformset_factory( 14 Transport, form=TransportForm, extra=0 15 ) 16 17 # idがnumのtripを取得する 18 if request.method == 'POST': 19 # 更新時は既に親モデルと繋がっている状態で渡されるから、いちいち外部キーを取得する必要はない 20 others = OtherFormSet(request.POST, queryset=other_model) 21 spots = SpotFormSet(request.POST, queryset=spot_model) 22 spot_first = SpotForm(request.POST, instance=spot_first_model) 23 transports = TransportFormSet(request.POST, queryset=transport_model) 24 # バリデーションのチェック 25 if others.is_valid() and spots.is_valid() and spot_first.is_valid() and transports.is_valid(): 26 trip.save() 27 # trip_id = Trip.objects.filter(id=num) 28 other = others.save() 29 for other_db in other: 30 other_db.trip = trip_model 31 other_db.save() 32 33 spot_first = spot_first.save() 34 35 spot = spots.save() 36 for spot_db in spot: 37 spot_db.trip = trip_model 38 spot_db.save() 39 40 # transport用にspotの情報を取得する 41 spot_id = Spot.objects.filter(trip=trip_model) 42 transport = transports.save() 43 for i in range(len(transport)): 44 transport[i].spot = spot_id[i] 45 transport[i].save() 46 47 return redirect(to='/make_trip/myPage') 48 49 # Getアクセス時の処理 50 else: 51 others = OtherFormSet(queryset=other_model) 52 spots = SpotFormSet(queryset=spot_model)[1:] 53 transports = TransportFormSet(queryset=transport_model) 54 spot_first = SpotForm(instance=spot_first_model) 55 56 params = { 57 'others': others, 58 'spots': spots, 59 'transports': transports, 60 'spot_first': spot_first, 61 'id': num, 62 } 63 return render(request, 'make_trip/edit.html', params)
modelformset
を使用しておりまして、複数のレコードを取得できるようにしております。
request.POST
では無事に地球
などを受け取れているのですが、spots = SpotFormSet(request.POST, queryset=spot_model)
の中身を見てみたところ、入っておりませんでした。
以下がrequest.POST
の中身になります。
request.post: <QueryDict: {'csrfmiddlewaretoken': ['VJFLV1PvaaHvNYv8rWIfjQUkIr9iPVY6aMC6C5DSwDyKOzWtV6CFqe5dMQtbvQ83'], 'title': ['ベルウッド'], 'trip_name': ['宇宙旅行'], 'start': ['2021-07-09'], 'end': ['2021-07-23'], 'spot_name': ['砂丘'], 'spot_time': ['2021-07-16 11:05:00'], 'spot_cost': ['111'], 'form-TOTAL_FORMS': ['3', '3'], 'form-INITIAL_FORMS': ['2', '0'], 'form-MIN_NUM_FORMS': ['0', '0'], 'form-MAX_NUM_FORMS': ['1000', '1000'], 'form-0-transport_name': ['タクシー'], 'form-0-transport_time': ['2021-07-15 11:05:00'], 'form-0-transport_fee': ['3'], 'form-1-spot_name': ['空港'], 'form-1-spot_time': ['2021-07-22 11:05:00'], 'form-1-spot_cost': ['2'], 'form-1-transport_name': ['電車'], 'form-1-transport_time': ['2021-07-09 11:05:00'], 'form-1-transport_fee': ['111'], 'form-2-spot_name': ['地球'], 'form-2-spot_time': ['2021-07-23 11:05:00'], 'form-2-spot_cost': ['111'], 'form-3-transport_name': ['エレベーター'], 'form-3-transport_time': ['2021-07-16 11:34'], 'form-3-transport_fee': ['11'], 'form-3-spot_name': ['月'], 'form-3-spot_time': ['2021-07-13 12:15'], 'form-3-spot_cost': ['100']}>
template
django
1{% block container %} 2{% load boost %} 3<form action="{% url 'edit' id %}" method="post"> 4 {% csrf_token %} 5 {{ spot_first.spot_name }} 6 {{ spot_first.spot_time }} 7 {{ spot_first.spot_cost }} 8 <div id="tran_spot_total"> 9 {{ transports.management_form }} 10 {{ spots.management_form }} 11 <div id="tranSpot_formset"> 12 {% for transport, spot in transports|zip:spots %} 13 <div id="input-transport-form-{{ forloop.counter0 }}"> 14 {{ transport.transport_name }} 15 {{ transport.transport_time }} 16 {{ transport.transport_fee }} 17 </div> 18 <div class="row mb-5" id="input-spot-form-{{ forloop.counter0 }}"> 19 {{ spot.spot_name }} 20 {{ spot.spot_time }} 21 {{ spot.spot_cost }} 22 </div> 23 {% endfor %} 24 </div> 25 <div id="tranSpot"></div> 26 </div> 27 <button type="button" id="addSpot">観光地を追加</button> 28 <div id="other_total"> 29 {{ others.management_form }} 30 <div id="other_formset"> 31 {% for other in others %} 32 <div id="input-form-{{ forloop.counter0 }}"> 33 {{ other.extra_name }} 34 {{ other.extra_cost }} 35 </div> 36 {% endfor %} 37 </div> 38 <div id="extra"></div> 39 </div> 40 <button type="button" id="addExtra">費用を追加</button> 41 <button type="submit">完成!</button> 42</form> 43{% endblock %} 44 45{% block js %} 46<script> 47 $(function(){ 48 // transpot部分の処理 49 var TotalManageElement = $('input#id_form-TOTAL_FORMS'); 50 var currentCount = parseInt(TotalManageElement.val()); 51 $('#addSpot').on('click', function(){ 52 var new_tranSpot = `<div class="row justify-content-end mb-5" id="input-transport-form-0"> 53 <div class="col-2"><h1 class="text-light">↓</h1></div> 54 <div class="col-3"> 55 <input type="text" name="form-0-transport_name" class="form-control" placeholder="移動手段" maxlength="30" id="id_form-0-transport_name"> 56 </div> 57 <div class="col-3"> 58 <input type="text" name="form-0-transport_time" class="form-control smallDate" placeholder="乗る時間" autocomplete="off" id="id_form-0-transport_time"> 59 </div> 60 <div class="col-3"> 61 <input type="number" name="form-0-transport_fee" class="form-control costs" placeholder="料金" id="id_form-0-transport_fee"> 62 </div> 63 </div> 64 65 <div class="row mb-5" id="input-spot-form-0"> 66 <div class="col-4"> 67 <input type="text" name="form-0-spot_name" class="form-control" placeholder="観光地" maxlength="50" id="id_form-0-spot_name"> 68 </div> 69 <div class="col-4"> 70 <input type="text" name="form-0-spot_time" class="form-control smallDate" placeholder="到着時間" autocomplete="off" id="id_form-0-spot_time"> 71 </div> 72 <div class="col-4"> 73 <input type="number" name="form-0-spot_cost" class="form-control costs" placeholder="滞在料金" id="id_form-0-spot_cost"> 74 </div> 75 </div>` 76 currentCount += 1 77 new_tranSpot = new_tranSpot.replace(/form-0/g, 'form-'+currentCount); 78 $('#tranSpot').append(new_tranSpot); 79 TotalManageElement.attr('value', currentCount); 80 81 }); 82 // other部分の処理 83 $('#addExtra').on('click', function(){ 84 var new_code = `<div class="row mb-3" id="input-form-0"> 85 <div class="col-6"><input type="text" name="form-0-extra_name" class="form-control" placeholder="追加の費用の項目" maxlength="50" id="id_form-0-extra_name"></div> 86 <div class="col-6"><input type="number" name="form-0-extra_cost" class="form-control costs" placeholder="追加の費用" id="id_form-0-extra_cost"></div> 87 </div>` 88 new_code = new_code.replace(/form-0/g, 'form-'+currentCount); 89 $('#extra').append(new_code); 90 currentCount += 1 91 TotalManageElement.attr('value', currentCount); 92 }); 93 }); 94</script> 95{% endblock %}
spots
とtransports
をzip
を使用することで、まとめて同じfor
の中で回しております。
また、観光地を追加
と費用を追加
のボタンを押した場合は、JS
の部分でフォームを追加するようにしております。
補足情報(FW/ツールのバージョンなど)
Python v3.7.7
Visual Studio Code v1.53.2
MacOS Darwin x64 20.3.0
Django 3.0.4
あなたの回答
tips
プレビュー