1
2

More than 3 years have passed since last update.

[Django]ModelChoiceFieldで動的に作成した選択肢がModel objectになるときの対処

Last updated at Posted at 2021-06-22

現象

ModelからFormに選択肢を追加したい場合、ModelChoiceFieldを用いるが、
選択肢がObjectとなってしまうときの対処法。
現象はこんな感じ。
object_choice.png

※ユーザープロフィールを作成するフォームに、国籍のフォームがあるイメージ。

この時点のコード

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')

name_choice.png

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)

参考

ModelChoiceField(英語)

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2