現象
ModelからFormに選択肢を追加したい場合、ModelChoiceFieldを用いるが、
選択肢がObjectとなってしまうときの対処法。
現象はこんな感じ。
※ユーザープロフィールを作成するフォームに、国籍のフォームがあるイメージ。
この時点のコード
country/models.py
from django.db import models
class country(models.Model):
name = models.CharField(max_length=100)
class Meta:
db_table = 'country'
user/profile/views.py
from django.shortcuts import render
from django.views.generic import FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from .forms import ProfileCreateForm
from country.models import Country
class ProfileCreateView(LoginRequiredMixin, FormView):
form_class = ProfileCreateForm
template_name = 'user/profile/create.html'
success_url = reverse_lazy('user:dashboard')
def get(self, request, **kwargs):
form = ProfileCreateForm()
form.fields['country'].queryset = Country.objects.all()
datas = {'form': form}
return render(self.request, self.template_name, datas)
user/profile/forms.py
from django import forms
from user.models import UserProfile
from country.models import Country
class ProfileCreateForm(forms.ModelForm):
country = forms.ModelChoiceField(queryset=Country.objects.all(), empty_label='Select your Country')
class Meta:
model = UserProfile
fields = ('name', 'country')
template/user/profile/create.html
{{form.country}}
対処法
ModelChoiceFieldのlabel_from_instance()をオーバーライドする。
country/forms.py
from django import forms
class CustomModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.name
user/profile/forms.py
from django import forms
from user.models import UserProfile
from country.models import Country
from country.forms import CustomModelChoiceField
class ProfileCreateForm(forms.ModelForm):
country = CustomModelChoiceField(queryset=Country.objects.all(), empty_label='Select your Country')
class Meta:
model = UserProfile
fields = ('name', 'country')
DB格納時にModel objectになる時の対応
user/profile/views.py
from django.shortcuts import render
from django.views.generic import FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from .forms import ProfileCreateForm
from country.models import Country
class ProfileCreateView(LoginRequiredMixin, FormView):
form_class = ProfileCreateForm
template_name = 'user/profile/create.html'
success_url = reverse_lazy('user:dashboard')
def get(self, request, **kwargs):
form = ProfileCreateForm()
form.fields['country'].queryset = Country.objects.all()
datas = {'form': form}
return render(self.request, self.template_name, datas)
def form_valid(self, form):
profile = form.save(commit=False)
profile.country = self.request.POST['country'] # ここ
profile.save()
return super().form_valid(form)