前提・実現したいこと
Djangoを用いて旅行の日程を作成するwebアプリを作成しているのですが、編集ページを作成して、前回入力していた部分は既に入力されている状態にしたいです。
一応、初期値として反映することはできているのですが、異なるformsetを交互に表示させるようにしたいです。
前提としまして、以下のような状態が旅行作成画面のデフォルトの状態になっておりまして、「観光地を追加」ボタンをクリックしたら、入力欄が追加されるようになる感じです。
発生している問題・エラーメッセージ
上が旅行作成ページの写真です。
そして、下が上で作成したものを編集するページになります。
旅行作成ページと同じような形で編集ページも表示したいのですが、上手くいきません。
該当のソースコード
forms.py
Django
1class SpotForm(forms.ModelForm): 2 def __init__(self, *args, **kwargs): 3 super().__init__(*args, **kwargs) 4 5 class Meta: 6 model = Spot 7 fields = ('spot_name', 'spot_time', 'spot_cost') 8 widgets = { 9 'spot_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '観光地'}), 10 'spot_time': forms.DateTimeInput(attrs={'class': 'form-control smallDate', 'placeholder': '到着時間', 'autocomplete': 'off'}), 11 'spot_cost': forms.NumberInput(attrs={'class': 'form-control costs', 'placeholder': '滞在料金'}) 12 } 13 14class TransportForm(forms.ModelForm): 15 def __init__(self, *args, **kwargs): 16 super().__init__(*args, **kwargs) 17 18 class Meta: 19 model = Transport 20 fields = ('transport_name', 'transport_time', 'transport_fee') 21 widgets = { 22 'transport_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '移動手段'}), 23 'transport_time': forms.DateTimeInput(attrs={'class': 'form-control smallDate', 'placeholder': '乗る時間', 'autocomplete': 'off'}), 24 'transport_fee': forms.NumberInput(attrs={'class': 'form-control costs', 'placeholder': '料金'}) 25 }
views.py
Django
1 2@login_required(login_url='/make_trip/') 3def test(request): 4 SpotFormSet = forms.modelformset_factory( 5 Spot, form=SpotForm, extra=1 6 ) 7 TransportFormSet = forms.modelformset_factory( 8 Transport, form=TransportForm, extra=1 9 ) 10 spots = SpotFormSet(queryset=Spot.objects.none()) 11 transports = TransportFormSet(queryset=Transport.objects.none()) 12 13 if request.method == 'POST': 14 spot_form = SpotForm(request.POST) 15 transports = TransportFormSet(request.POST) 16 17 # 保存したtripの情報を取得 18 trip_id = Trip.objects.filter(group=group_id).first() 19 20 spot_save = spot_form.save(commit=False) 21 spot_save.trip = trip_id 22 spot_save.save() 23 24 spot = spots.save(commit=False) 25 for spot_db in spot: 26 spot_db.trip = trip_id 27 spot_db.save() 28 29 # transport用にspotの情報を取得する 30 spot_id = Spot.objects.filter(trip=trip_id) 31 print('spot_id:', spot_id) 32 transport = transports.save(commit=False) 33 for i in range(len(transport)): 34 transport[i].spot = spot_id[i] 35 transport[i].save() 36 37 return redirect(to='/make_trip/myPage') 38 39 params = { 40 'spots': spots, 41 'transports': transports 42 } 43 44 return render(request, 'make_trip/test.html', params) 45 46 47# 編集用のページを作成 48 49@login_required(login_url='/make_trip/') 50def test_edit(request, num): 51 spot_model = Spot.objects.filter(trip=trip_model.id) 52 transport_model = Transport.objects.filter(spot__in=spot_model) 53 SpotFormSet = forms.modelformset_factory( 54 Spot, form=SpotForm, extra=0 55 ) 56 TransportFormSet = forms.modelformset_factory( 57 Transport, form=TransportForm, extra=0 58 ) 59 60 # idがnumのtripを取得する 61 if request.method == 'POST': 62 # 更新時は既に親モデルと繋がっている状態で渡されるから、いちいち外部キーを取得する必要はない 63 spots = SpotFormSet(request.POST, queryset=spot_model) 64 transports = TransportFormSet(request.POST, queryset=transport_model) 65 66 spot = spots.save(commit=False) 67 for spot_db in spot: 68 spot_db.trip = trip_model 69 spot_db.save() 70 71 # transport用にspotの情報を取得する 72 spot_id = Spot.objects.filter(trip=trip_model) 73 print('spot_id:', spot_id) 74 transport = transports.save(commit=False) 75 for i in range(len(transport)): 76 transport[i].spot = spot_id[i] 77 transport[i].save() 78 79 return redirect(to='/make_trip/myPage') 80 81 # Getアクセス時の処理 82 else: 83 spots = SpotFormSet(queryset=spot_model) 84 transports = TransportFormSet(queryset=transport_model) 85 86 params = { 87 'spots': spots, 88 'transports': transports 89 } 90 return render(request, 'make_trip/edit.html', params)
spotもtransportもModelformset
を使用しておりまして、template内でそれぞれforを回して、初期値を設定していくようにしています。
また、一応補足としまして、trip_id
などは取得済みだと考えていただければ大丈夫です。
html
1<form action="" method="post"> 2 {% csrf_token %} 3 <div id="tranSpotDefault"> 4 <div id="tranSpot_formset"> 5 {{ transports.management_form }} 6 {% for transport in transports %} 7 <div class="row justify-content-end mb-5" id="input-transport-form-{{ forloop.counter0 }}"> 8 <div class="col-2"><h1 class="text-light">↓</h1></div> 9 <div class="col-3"> 10 {{ transport.transport_name }} 11 </div> 12 <div class="col-3"> 13 {{ transport.transport_time }} 14 </div> 15 <div class="col-3"> 16 {{ transport.transport_fee }} 17 </div> 18 </div> 19 {% endfor %} 20 {{ spots.management_form }} 21 {% for spot in spots %} 22 <div class="row mb-5" id="input-spot-form-{{ forloop.counter0 }}"> 23 <div class="col-4"> 24 {{ spot.spot_name }} 25 </div> 26 <div class="col-4"> 27 {{ spot.spot_time }} 28 </div> 29 <div class="col-4"> 30 {{ spot.spot_cost }} 31 </div> 32 </div> 33 {% endfor %} 34 </div> 35 </div> 36 <div id="tranSpot"></div> 37 <button class="btn btn-outline-success" type="button" id="addSpot">観光地を追加</button> 38 <div class="col-6 col-md-4 col-xl-3 col-xs-12 mx-auto"> 39 <button type="submit" class="btn btn-light btn-block border-0" style="background-color: rgba(191, 202, 63, 0.99);">完成!</button> 40 </div> 41</form>
試したこと
今回投稿したコードだと、template
内でfor
が別々に回るので、こう
views.pyの中でtransport
とspot
を一つのリストや辞書にまとめることによって、template
内で交互にそれぞれを表示することができないかやってみたのですが、無理そうでした。
また、template内でrange
やlen
を使って、インデックス
を指定することに表示できないかやってみたのですが、こちらも無理そうでした。
補足情報(FW/ツールのバージョンなど)
Python v3.7.7
Visual Studio Code v1.53.2
MacOS Darwin x64 20.3.0
Django 3.0.4
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/07/11 02:23