はじめに
DjangoでFormを使ったviewを作ってて以下のような不便を感じたことはありませんか?
「1つのviewに2つのFormを表示してるんだけど、同じname属性を持ったinputが2つできちゃって、POSTがわかりずらい」
こんな時に役に立つのが、Formのインスタンス作成時に指定できるprefixです
コードの紹介
サンプルとして定義したmodels.pyとforms.py
今回はModelFormでサンプルを示すので、事前にmodels.pyとそれに基づいたforms.pyを定義しますね
from django.db import models
# Create your models here.
class TestModel(models.Model):
name = models.CharField(max_length=100)
class SampleModel(models.Model):
name = models.CharField(max_length=100)
class TestForm(forms.ModelForm):
class Meta:
model = models.TestModel
fields = '__all__'
class SampleForm(forms.ModelForm):
class Meta:
model = models.SampleModel
fields = '__all__'
prefixを使わないviewsの書き方
class CreateTest(generic.CreateView):
template_name = 'reg.html'
form_class = forms.TestForm
model = models.TestModel
def post(self, request, *args, **kwargs):
print(request.POST)
return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['form2'] = forms.SampleForm()
return ctx
このviewを以下のtemplateで表示してみます
<form method="post">
{{ form }}
{{ form2 }}
<button>submit!</button>
</form>
以下のようになります
ふたつのInput要素のname属性が重複してしまっているのがわかりますね
2つのInput要素には「ほげ」「ふが」と順に入力してsubmitボタンで送信してみます
以下のようにとれました
※csrf_tokenの中身は長いので省略してます
<QueryDict: {'csrfmiddlewaretoken': [''], 'name': ['ほげ', 'ふが']}>
これだとどっちのFormにどっちを渡せばいいかわからないですよね。templateで定義している順番でリストも構成されているので、requesr.POST['name'][0]と指定してあげてもいいですが、またinput要素が追加されてが順番が変わってしまうかもしれません
prefixを使ったviewsの書き方
こんなときは「name属性の値を変えてしまいたい」と思いますよね。けどModelFormを使っているので、簡単に変えることはできません
そんなときに役に立ちそうなのがprefixです
class CreateTest(generic.CreateView):
template_name = 'reg.html'
form_class = forms.TestForm
model = models.TestModel
success_url = 'qiita'
def post(self, request, *args, **kwargs):
print(request.POST)
return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['form2'] = forms.SampleForm(prefix='test')
return ctx
form2のinput要素のnameが[prefixに指定した文字列-元のname属性名]となりました
これによりrequest.POSTで受け取ると別々の値として受け取ることができます
<QueryDict: {'csrfmiddlewaretoken': [''], 'name': ['ほげ'], 'test-name': ['ふが']}>
結言
prefixを使うと重複した名前をもったinput要素をうまい感じに管理できました