【初めてのDjango Web開発】モデルと紐付いた投稿フォームとCSSの適用

PythonのフレームワークであるDjangoでは、modelで定義したフィールドをそのまま使って自動生成されるフォームを簡単に作ることができます。その作成方法を初心者向けにメモしておきます。ただそれだけでもとても便利ですが、さらにCSSを適用して、見た目も良くしてみます。

使用しているDjango version は4.2.16です。

models.pyの作成

投稿データをsqlite3で保存するためのテーブルを定義します。

尚フォルダ構成はこれに限定されるものではありませんので、ご自分の環境に合わせて参考にしてください。

models.py

fumProj/myblog/models.py

from django.db import models

# Create your models here.
class Post(models.Model):
    id=models.AutoField(primary_key=True, verbose_name="ID")
    title=models.CharField(max_length=128, verbose_name="タイトル")
    body = models.TextField(max_length=255,  verbose_name="本文")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新日")

    def __str__(self):
        return self.title

forms.pyの作成

models.pyと同じ階層にforms.pyを作成し、django.forms.ModelFormクラスを継承させます。

forms.py

fumProj/myblog/forms.py

from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post                          # ←紐付くモデル名
        fields = ["title", "body"]    # ←紐付くフィールド名

Metaクラスのクラス変数(model)でPostモデルと紐づけるだけです。

『model = Post」』でPostモデルと紐付かせ、
『fields = ["title", "body"] 』で紐付かせたいフィールドをリスト配列で複数記述します。

urls.pyとviews.pyの作成

作成したアプリ毎にurls.pyを作成すると、複数のアプリを切り替えることができます。

urls.py

fumProj/myblog/urls.py

from django.urls import path
from . import views

# blogアプリ用urlpatterns
urlpatterns = [
    path("", views.index, name="post_index"), 
    path("create/", views.post_create, name="post_create"),
]

fumProj/fumProj/urls.py

from django.contrib import admin
from django.urls import path, include

# project全体のurlpatterns
urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include("myblog.urls")), 
]

views.py

fumProj/myblog/views.py

from django.shortcuts import render, redirect
from django.views import View

from .forms import PostForm

# 新規投稿用(classベースview)
class PostCreateView(View):
    def get(self, request):
        form=PostForm()       # ← # PostForm のインスタンスを生成
        # "form"というkeyでformインスタンスを渡します。
        return render(request, "myblog/postCreateform.html", {"form": form}) 
    
    def post(self, request):
        form = PostForm(request.POST)
        if form.is_valid():  # ←validationがOKなら
            form.save()    # ←保存
            return redirect("post_index")  # ←投稿一覧にリダイレクト
        return render(request, 'myblog/postCreateform.html', {"form": form})

post_create = PostCreateView.as_view()

base.htmlとpostCreateform.htmlの作成

base.html

fumProj/myblog/templates/myblog/base.html

<!DOCTYPE html>
{% load static %}
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>myBlog | 初めてのdjango</title> 
    <link rel="stylesheet" href="{% static '/css/common.css' %}">
</head>
<body>
    <div class="container" >
        {% block content %} {% endblock %}
    </div>
    <footer><small>by Django ver 4.2.16</small></footer>
</body>
</html>

postCreateform.html

fumProj/myblog/templates/myblog/postCreateform.html

{% extends "myblog/base.html" %}
{% load static %}
{% block content %}
    <h2>新規作成画面</h2>
    <form class="create_form"  action=""  method="post">
        {% csrf_token %}
        {{ form.as_p }}   # ←これを記載するだけ自動で展開される!!
        <button type="submit" class="submit-btn">登録</button>
    </form>
    <a class="left_pos" href="{% url "post_index" %}">トップ画面に戻る</a>
{% endblock %}

form変数にはフィールドの情報が格納されており、<form>タグの中に{{ form }}とすれば、HTMLに自動で展開されます。

{{ form.as_p }}とすれば、<p>タグで各フィールドが囲まれて展開されます。.as_p以外にも.as_tableとすればテーブル形式で、.as_ulとすればリスト形式で表示されます。

しかし、このままだと各フィールドは整頓されていません。

改善前の投稿フォーム

{{ form.as_p }}で展開した場合の投稿フォームです。

改善前の投稿フォーム

これでも十分使えますが、右側の余白が少し気になります。

このHTMLはどうなっているのか、「ページのソースの表示」で確認してみると。

ソースの表示

<form class="create_form" action="" method="post">
    <input type="hidden" name="csrfmiddlewaretoken"  
  value="J6oqbh2pj2ku9zbCMoVeB0JH1IrOlrBYi3ZQ0EJg1ERSfJjtaRwexHrBvFssQmR6">
    <p>
         <label for="id_title">タイトル:</label>
         <input type="text" name="title" maxlength="128" 
      required  id="id_title">
  </p>

  <p>
         <label for="id_body">本文:</label>
         <textarea name="body" cols="40" rows="10" 
     maxlength="255" required  id="id_body"></textarea>
   </p>
    <button type="submit" class="submit-btn">登録</button>
</form>

各フィールドが<p>タグで囲まれており、タイトルにはid="id_title"、本文にはid="id_body"とidが付けられていました。

cssを適用出来そうですので、cssでフォームを少し改善してみます。

改善後の投稿フォーム

改善後の投稿フォーム

右側の余白も消え、広く使えそうです。

適用したcssは次の通りです。

style(common.css)

.create_form p{
    display: flex;
    justify-content: space-between;
}

.create_form #id_title,
.create_form #id_body{
    flex: 1;
    padding: 4px;
    margin: 0 8px;
    box-sizing: border-box;
}

.create_form p > label{
    display: inline-block;
    width: 80px;
    text-align: right;
}

{{ form.as_p }}と1行書くだけで自動でできるので、このままでしか使えないのかと思っていたら、少しぐらいなら自分の好みに合わせて変更できそうです。

以上です。😁

Follow me!