Python | Django | FormSetを利用した複数フォームの表示方法
公開日:2021/7/14
Pythonには,DjangoというWebアプリケーションフレームワークがある.フレームワークのため,Djangoを利用するとWebアプリを通常よりも短時間で開発することが可能になる.
前記事にて,「htmlファイルを利用したフォーム設定方法」を記した.前記事での設定をそのまま引き継いだ上で,本記事では,「FormSetを利用した複数フォームの表示方法」を以下4つの構成にて記す.
◆実施環境
Python 3.8.8
Django 3.2.3
■FormSetを利用した複数フォームの表示方法
FormSet(フォームセット)を利用すると複数のフォームを同じ画面に表示することができる.
“form_app/views.py"に追記し,以下のように編集する.
from django.shortcuts import render
from django.forms import formset_factory # 追記箇所
from . import forms
def index(request):
return render(request, 'form_temp/index.html')
def form_page(request):
form = forms.ChocolateInfo()
if request.method == 'POST':
form = forms.ChocolateInfo(request.POST)
if form.is_valid():
print('submission is successful')
print(form.cleaned_data)
else:
print('submission is failed')
return render(
request,'form_temp/form_page.html', context={
'form':form
}
)
def form_bird(request):
form = forms.BirdModelForm()
if request.method == 'POST':
form = forms.BirdModelForm(request.POST)
if form.is_valid():
form.save()
return render(
request, 'form_temp/form_bird.html', context={'form':form}
)
def form_set_name(request): # 以下追記箇所
TestFormset = formset_factory()
“form_app/forms.py"に追記し,以下のように編集する.
from django import forms
from django.core import validators
from.models import Bird
class ChocolateInfo(forms.Form):
chocolate_name = forms.CharField(label='チョコレート名', max_length=50)
chocolate_maker = forms.CharField(label='チョコレートメーカー', max_length=50)
mail = forms.EmailField(label='メールアドレス')
confirmed_mail = forms.EmailField(label='メールアドレス再入力')
is_available_for_sale = forms.BooleanField(label='販売中')
birthday = forms.DateField(required=False, label='開発日')
price = forms.DecimalField(initial=300, max_value=1000, label='価格',validators=[validators.MinValueValidator(1, message='1以上にしてください')])
flavor = forms.ChoiceField(choices=(
(1,'Original Chocolat'),
(2,'Double Chocolat'),
(3,'Original White'),
(4,'Rich Matcha'),
), widget=forms.RadioSelect, label='味')
maker_factory = forms.MultipleChoiceField(choices=(
(1,'Ibaraki Moriya-city'),
(2,'Saitama Sakado-city'),
(3,'Aichi Inazawa-city'),
(4,'Osaka Takatsuki-city'),
), widget=forms.CheckboxSelectMultiple, label='メーカー工場')
homepage = forms.URLField(
label='ホームページ',
widget=forms.TextInput(attrs={'class':'url_class','placeholder':'https://www.shelokuma.com'}))
def __init__(self,*args,**kwargs):
super(ChocolateInfo, self).__init__(*args,**kwargs)
self.fields['flavor'].widget.attrs['id']='id_flavor'
self.fields['maker_factory'].widget.attrs['class']='maker_factory_class'
def clean_chocolatename(self):
chocolate_name = self.cleaned_data['chocolate_name']
if not chocolate_name.startswith('F'):
raise forms.ValidationError('名前は「F」から始めてください')
def clean(self):
cleaned_data = super().clean()
mail = cleaned_data['mail']
confirmed_mail = cleaned_data['confirmed_mail']
if mail != confirmed_mail:
raise forms.ValidationError('メールアドレスが一致しません')
class BaseForm(forms.ModelForm):
def save(self,*args,**kwargs):
print(f'{self.__class__.__name__} is successful')
return super(BaseForm, self).save(*args,**kwargs)
class BirdModelForm(BaseForm):
birdname = forms.CharField(label='Birdname')
title = forms.CharField(label='Title')
review = forms.CharField(
label='review', widget=forms.Textarea(attrs={
'rows':15,
'cols':25,}))
author = forms.CharField(label='Author')
class Meta:
model = Bird
fields ='__all__'
def save(self,*args,**kwargs):
ipt = super(BirdModelForm, self).save(commit=False,*args,**kwargs)
ipt.birdname = ipt.birdname.lower()
print(type(ipt))
print('save is successful')
ipt.save()
return ipt
def clean_birdname(self):
birdname = self.cleaned_data.get('birdname')
if birdname == 'this is error':
raise validators.ValidationError('そのbirdnameはエラーです')
return birdname
def clean_title(self):
title = self.cleaned_data.get('title')
if title == 'this is error':
raise validators.ValidationError('そのtitleはエラーです')
return title
def clean_review(self):
review = self.cleaned_data.get('review')
if review == 'this is error':
raise validators.ValidationError('そのreviewはエラーです')
return review
def clean_author(self):
author = self.cleaned_data.get('author')
if author == 'this is error':
raise validators.ValidationError('そのauthorはエラーです')
return author
def clean(self):
cleaned_data = super().clean()
author = cleaned_data.get('author')
checking_exists = Bird.objects.filter(author=author).first()
if checking_exists:
raise validators.ValidationError('そのauthorはすでに存在しています')
class FormSetName(forms.Form): # 以下追記箇所
name = forms.CharField(label='名前')
birthplace = forms.CharField(label='出身地')
“form_app/views.py"に追記し,以下のように編集する.
from django.shortcuts import render
from django.forms import formset_factory
from . import forms
def index(request):
return render(request, 'form_temp/index.html')
def form_page(request):
form = forms.ChocolateInfo()
if request.method == 'POST':
form = forms.ChocolateInfo(request.POST)
if form.is_valid():
print('submission is successful')
print(form.cleaned_data)
else:
print('submission is failed')
return render(
request,'form_temp/form_page.html', context={
'form':form
}
)
def form_bird(request):
form = forms.BirdModelForm()
if request.method == 'POST':
form = forms.BirdModelForm(request.POST)
if form.is_valid():
form.save()
return render(
request, 'form_temp/form_bird.html', context={'form':form}
)
def form_set_name(request): # 以下追記箇所
TestFormset = formset_factory(forms.FormSetName)
formset = TestFormset()
return render(
request, 'form_temp/form_set_name.html',
context = {'formset':formset}
)
“form_project/templates/form_temp"に"form_set_name.html"を作成する.以下のような構成になる.
“form_set_name.html"を以下のように編集する.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Form</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<form method='POST'>
{% csrf_token %}
{{ formset.as_table }}
<input type="submit" value="submit">
</form>
</body>
</html>
“form_app/urls.py"を追記し,以下のように編集する.
from django. urls import path
from . import views
app_name = 'form_application'
urlpatterns = [
path('', views.index, name='index'),
path('form_page/', views.form_page, name='form_page'),
path('form_bird/', views.form_bird, name='form_bird'),
path('form_set_name/', views.form_set_name, name='form_set_name'), # 追記箇所
]
ターミナルを開き,”conda activate 仮想環境名”を実行し,仮想環境に移行する(移行方法の詳細はこちら)."cd form_project"を実行することによって,”form_project”のディレクトリに移動する.その後,”python manage.py runserver”を実行する.以下が出力される.
(djangoenv) C:\Users\shiro\Desktop\210517_python development\myformtest\form_project
>python manage.py runserver
System check identified no issues (0 silenced). # 以下出力箇所
July 14, 2021 - 14:39:30
Django version 3.2.3, using settings 'form_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
上記の"http://127.0.0.1:8000″をクリックする.以下ページに遷移する.
ブラウザのURLに"http://127.0.0.1:8000/form_application/form_set_name"を入力すると,以下ページに遷移する."formset.as_table"に基づく表記になる.
“form_set_name.html"を,"formset.as_table"から"formset.as_p"に変更し,以下のように編集する.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Form</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<form method='POST'>
{% csrf_token %}
{{ formset.as_p }} # 変更箇所
<input type="submit" value="submit">
</form>
</body>
</html>
上記を保存し,ブラウザのURLに"http://127.0.0.1:8000/form_application/form_set_name"を入力すると,以下ページに遷移する."formset.as_p"に基づく表記になる.
“form_app/views.py"を以下のように編集する."extra=4″を入力することによって,フォームが4つ出来る.
from django.shortcuts import render
from django.forms import formset_factory
from . import forms
def index(request):
return render(request, 'form_temp/index.html')
def form_page(request):
form = forms.ChocolateInfo()
if request.method == 'POST':
form = forms.ChocolateInfo(request.POST)
if form.is_valid():
print('submission is successful')
print(form.cleaned_data)
else:
print('submission is failed')
return render(
request,'form_temp/form_page.html', context={
'form':form
}
)
def form_bird(request):
form = forms.BirdModelForm()
if request.method == 'POST':
form = forms.BirdModelForm(request.POST)
if form.is_valid():
form.save()
return render(
request, 'form_temp/form_bird.html', context={'form':form}
)
def form_set_name(request):
TestFormset = formset_factory(forms.FormSetName, extra=4) # 変更箇所
formset = TestFormset()
return render(
request, 'form_temp/form_set_name.html',
context = {'formset':formset}
)
上記を保存し,ブラウザのURLに"http://127.0.0.1:8000/form_application/form_set_name"を入力すると,以下ページに遷移する."formset.as_p"に基づくフォームが4つ出来上がった.
“form_app/views.py"を以下のように編集する.
from django.shortcuts import render
from django.forms import formset_factory
from . import forms
def index(request):
return render(request, 'form_temp/index.html')
def form_page(request):
form = forms.ChocolateInfo()
if request.method == 'POST':
form = forms.ChocolateInfo(request.POST)
if form.is_valid():
print('submission is successful')
print(form.cleaned_data)
else:
print('submission is failed')
return render(
request,'form_temp/form_page.html', context={
'form':form
}
)
def form_bird(request):
form = forms.BirdModelForm()
if request.method == 'POST':
form = forms.BirdModelForm(request.POST)
if form.is_valid():
form.save()
return render(
request, 'form_temp/form_bird.html', context={'form':form}
)
def form_set_name(request):
TestFormset = formset_factory(forms.FormSetName, extra=4)
formset = TestFormset(request.POST or None) # 編集箇所(36~39行目)
if formset.is_valid():
for form in formset:
print(form.cleaned_data)
return render(
request, 'form_temp/form_set_name.html',
context = {'formset':formset}
)
上記を保存し,"http://127.0.0.1:8000/form_application/form_set_name"に移動する.移動後,各項目に入力し,"submit"をクリックする.
クリックすると,ターミナルには以下が出力される.4人分の名前と出身地を入力する欄があるが,全て入力しなくてもエラーは発生しない.
{'name': '坂本龍馬', 'birthplace': '土佐'}
{'name': '勝海舟', 'birthplace': '江戸'}
{'name': '西郷隆盛', 'birthplace': '薩摩'}
{}
[14/Jul/2021 16:29:53]
"POST /form_application/form_set_name/ HTTP/1.1" 200 1775
“form_set_name.html"を以下のように編集する.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Form</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<form method='POST'>
{% csrf_token %}
{{ formset.management_form }} # 以下編集箇所(13~17行目)
{% for form in formset %}
{{ form.as_p }}
<hr>
{% endfor %}
<input type="submit" value="submit">
</form>
</body>
</html>
上記を保存し,"http://127.0.0.1:8000/form_application/form_set_name"に移動する.<hr>が含まれているので,区切りがされている以下ページとなる.
以上