先日、Webアプリケーションを作製していたところ、詳細画面に別モデルの登録機能をつけたい.....となったときにDetailViewで詳細画面を作成していたため、登録機能をつけるのに難航してしまった。
from django.views.generic import CreateView, TemplateView, ListView, DetailView
class TestDetailView(DetailView):
model = TestModel
def post(self, request, *args, **kwargs):
form = Test2Form(request.POST)
if form.is_valid():
print("バリデーションOK")
form.save()
else:
print("バリデーションNG")
print(form.errors)
return redirect("test:home")
#models.py
class TestModel(models.Model): #詳細表示したいモデル
deadline_m = models.DateField(verbose_name= '締め切り日',)
start_m = models.DateField(verbose_name= '開始日',)
end_m = models.DateField(verbose_name= '終了日',)
def __str__(self):
return (self.start_m) + (self.end_m)
class Test2Model(models.Model): #登録したいモデル
省略
#froms.py
class Test2Form(ModelForm):
class Meta:
model = Test2Model
fields = ['test', 'ooo', 'iii']
これで DetailViewにフォームが表示されて登録できるぞ.....
と思っていたらフォームが表示されない。
ということでCreateViewで作れないかと検討した。
解決策
結果からいうと、 CreateView で def get_context_data を使い、自身のpkを取得して、データベースからpkのレコードを検索させて保存しておくという方法である。
修正前
#views.py
class DetailAndPostView(DetailView):
template_name = 'test/DandP.html'
model = TestModel
context_object_name = 'MI'
def post(self, request, *args, **kwargs):
form = Test2(request.POST)
if form.is_valid():
print("バリデーションOK")
form.save()
else:
print("バリデーションNG")
print(form.errors)
return redirect("リダイレクト先")
html
<div class="p3">
<a>締切日</a><br>
<a>{{ MI.deadline_m }}</a>
</div>
<div class="p4">
<a>開始日</a>
<a>{{ MI.start_m }}</a>
</div>
<div class="p4">
<a>終了日</a>
<a>{{ MI.end_m }}</a>
</div>
修正後
class DetailAndPost(CreateView):
template_name = 'account/DandP.html'
form_class = Test2Form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) #恒例のもうおまじないみたいなやつ
Xcode = self.kwargs['pk'] #ここで自身のpkを変数に保存しておく
start = TestModel.objects.get(code_m=Xcode).start_m #pk で データベースから検索させヒットしたものを変数に保存
end = TestModel.objects.get(code_m=Xcode).end_m #上に同じ
deadline = TestModel.objects.get(code_m=Xcode).deadline_m #上に同じ
context.update({ #context.update で名前をつけ、変数に保存されているデータをhtml上で使えるようにする。
'start': start,
'end': end,
'deadline': deadline
})
return context #値を返す
html
<div class="p3">
<a>締切日</a><br>
<a>{{ deadline }}</a>
</div>
<div class="p4">
<a>開始日</a>
<a>{{ start }}</a>
</div>
<div class="p4">
<a>終了日</a>
<a>{{ end }}</a>
</div>
これでうまくいきました!
解説
DetailView では オブジェクト名を指定してあるpkの値のレコードを参照できたが、 CreateViewにはその機能はないので
def get_context_data 内で 自身のpk を取得し、 データベースで検索させて データをある名前で保存し、使えるようにするといったものである。
感想
Djangoを使って思いましたが、いろいろと不便なことが多い気がする。 かゆいところにまったく手が届かないので、かゆいところがでてきた場合には毎度毎度、孫の手を作ってかゆいところの解消をしている気がする。
Django初心者だからそう感じるんですかねぇ... Django歴長いひとの感想待ってます。