python,djangoでフォームとリストを同時に出力したい。
えっ?そんなこと簡単なんじゃないのと思われるかもしれませんがちょっとコツが要ります。
まずなんで同時に出力できないの?ということを説明しますね。
urls.pyを見てみましょう。
path('<int:pk>/', views.ListView.as_view(), name='detail'),
urlで使用できる関数は以下で定義されます。
views.ListView.as_view()
これって例えば
views.ListView.as_view(), views.FormView.as_view(),
とかやってフォームとコメントの一覧を1ページに出力しようとするとエラーが出ます。 これってdjango特有の不便さなんですかね?それともwebのフレームワークはおおむねそういうものなの?知っている方いたら教えてちょ!
というわけで、冒頭に話した 「えっ?そんなこと簡単なんじゃないのと思われるかもしれませんがちょっとコツが要ります。」
という話が浮上してきます。
というわけでふたつの関数をドッキングさせます。
リストビュー。
class ListView(generic.ListView):
model = Post
フォームビュー。
class PostForm(forms.ModelForm):
success_url = reverse_lazy('board:board')
template_name = 'board/board.html'
class Meta:
model = Post
fields = "__all__"
フュージョン!!
class ListView(generic.ListView, ModelFormMixin):
model = Post
form_class = PostForm
success_url = reverse_lazy('board:board')
template_name = 'board/board.html'
paginate_by = 15
def get(self, request, *args, **kwargs):
self.object = None
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = None
self.object_list = self.get_queryset()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
詳しくは滝川成人先生のブログを見てほしいですが僕の方でも解説。
https://torina.top/detail/337/
class ListView(generic.ListView, ModelFormMixin):
ListViewをベースにしてFormをミックスします。
リストに使うモデルであるPOSTとフォーム部分に使うモデルフォームであるPostFormを定義します。
model = Post
form_class = PostForm
フォームとリストを使うテンプレートを定義しましょう。
success_url = reverse_lazy('board:board')
template_name = 'board/board.html'
上は成功時にリダイレクトするURLで下はフォームを使いたいURL。
これはページネーションのページ数。
paginate_by = 15
これはごめんなさい。分かりません!
def get(self, request, *args, **kwargs):
self.object = None
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = None
self.object_list = self.get_queryset()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
super()が継承に使うものということしかわかりません!!
これはPostのリストを新着順にする魔法。
def get_queryset(self):
return Post.objects.order_by('-date')
一番上から古いものが表示されます。
これで基本は終わり。でもちょっと補足します。
リストをベースにしてフォームをミックスするといいましたが
フォームビューとリストビューを別個に作り、TemplateResponseMixinと書く方法があります。
class FormAndListView(FormView, ListView, TemplateResponseMixin):
でもこの方法だとListViewがベースにならないため(だと思われる)ページネーションが出来ないです。気を付けましょうね。