以前、モデルクラスを使用せず、アプリケーションフォルダ内のforms.pyにFormクラスを継承したフォームクラスを定義して、Viewクラスと紐づけてテンプレートに渡すアプリの作成について解説しました。
このアプリは、データベースとの連携を必要とせず、ユーザーからのリクエストに応じてviews.py内に設定した独自関数を実行し、その結果をユーザーに返すというシンプルな仕組みのため活用シーンが多岐に考えられますが、デメリットがデータベースとの連携を想定していないことでした。(下記にリンク先を掲載します。)
今回は、モデルクラスを定義し、forms.pyでModelFormを継承したフォームクラスを定義します。また、このフォームクラス内で、編集対象となるモデルクラスとモデルクラスのフィールドを引き渡すことでモデルクラスの保存・編集をフォーム操作で可能にすることが出来ます。
今回の作成例として、簡単な日記アプリを作成していきたいと思います。
初めに、今回作成するアプリに、ブラウザからアクセスがあった際、フォーム画面を表示するまでの流れを図解します。この流れを意識して頂けば、必要なファイルが自ずとご理解頂けるかと思います。

①HTTPリクエスト:ブラウザからトップページにアクセス
②pj/urls.pyにリクエスト転送:サーバーソフトが、プロジェクトのurls.pyにリクエストを転送
③app/urls.pyにリクエスト転送:プロジェクトのurls.pyにはトップページへのアクセスがあった際はアプリケーションのurls.pyにリクエストを転送するように設定しているので、リクエストが転送される。
④views.pyにリクエスト転送:アプリケーションのurls.pyには、トップページにアクセスがあった際のビュークラスとテンプレートが紐づけられており、ビュークラスにリクエストが転送される。
➄app/forms.py:リクエストを受け取ったビュークラス(後述のSampleCreateModelForm)は、フォームクラスを引き受けるように設定されているので、ビュークラスがforms.pyに対してフォームクラスの引き渡しを要求する。
⑥app/models.py:➄で引き渡しを要求されたフォームクラス(後述のSampleFormModel)は、モデルクラスを引き受けるように設定されているので、フォームクラスがmodels.pyに対してモデルクラス(後述のSampleModel)の引き渡しを要求する。
➆app/forms.py:モデルクラス(後述のSampleModel)を受け取ったフォームクラス(後述のSampleCreateModelForm)がビュークラスに引き渡される。
➇、➈views.py⇔templates:ビュークラスがテンプレートをレンダリング(書き換え)する。その際、テンプレート内のテンプレートタグ({{ form.as_p }}など)を見つけたら、ビュークラスがテンプレートに必要な情報を引き渡してテンプレートを完成させる。
⑩、⑪views.py⇔ブラウザ:完成されたhtmlファイルがブラウザに引き渡されて、フォーム画面が表示される。
以降で具体的な作成手順の解説に進みます。
models.pyの作成
models.Modelを継承してSampleModelというモデルを定義しています。
from django.db import models
from django.utils import timezone
# Create your models here.
class SampleModel(models.Model):
title = models.CharField('タイトル', max_length=100)
text = models.TextField('本文')
created_at = models.DateTimeField('作成日', default=timezone.now)
def __str__(self):
return self.title
このモデルを基にデータを作成していくと、下記のようなテーブルがデータベースに作成されていきます。
models.pyのモデルに定義するフィールド(上記の例では、title, text, created_at)は、テーブルのカラム名(列名)に該当します。
フィールドには、djangoが用意している様々なフィールドを適用することができます。どのフィールドを適用するか?はカラムにどんなデータを入力していくかに合わせて使い分けていきます。
(例、入力するデータ=テキスト => CharField または TextField。)
(例、入力するデータ=日時 => DateTimeField。)
ID | title | text | created_at |
1 | 1回目の投稿 | おはようございます。 | 2023-01-02 |
2 | 2回目の投稿 | こんにちは。 | 2023-01-03 |
forms.py
forms.ModelFormを継承してSampleFormModelというフォームモデルを定義します。
forms.ModelFormを継承すると、モデルに定義したモデルクラスのフィールドをフォームに反映することが出来ます。
forms.ModelFormを継承する場合、クラス内にMetaクラスを定義します。
そして、Metaクラス内にmodelとfieldを定義します。
・model:models.pyで定義したモデルクラスを渡します。
・field:下記3通りの記述方法があります。
フィールド全て:fields = “__all__”
フィールドの一部:fields = [“field1”, “field2”]
一部のフィールドを除く:exclude = “除外するフィールド”
from .models import SampleModel
from django.db import models
from django import forms
class SampleFormModel(forms.ModelForm):
class Meta:
model = SampleModel
fields = "__all__"
def __init__(self, *args, **kwargs):
for field in self.base_fields.values():
field.widget.attrs["class"]="form-control"
super().__init__(*args, **kwargs)
フォームクラス内のMetaクラスに、モデルクラスを引き渡したので、下記のようなフォーム入力欄を用意したことになります。後程のテンプレートでこれをブラウザに表示できるようにします。(現時点では、まだテンプレートに引き渡していないので、下記のブラウザに下記のように表示することはできません。下記画像はあくまでイメージとして捉えて下さい。)

※init関数の部分は、Bootstrapの「form-control」クラスを各フィールドに適用するために実装しています。必須ではありませんので、必要に応じて実装を検討下さい。
views.py
ModelFormを使用する場合、ビュークラスにはCreateViewを継承したビュークラスを定義します。
CreateViewは、template_nameとform_classを引き渡すことで、引き渡したテンプレートに対してフォームを反映させることが出来ます。また、そのフォームから入力されたデータはフォームに紐づけられているモデルクラスを通じてデータベースに記録されます。
・template_name:フォームを表示するテンプレートを渡します。
・form_class:forms.pyでModelFormを継承して作成したフォームクラスを渡します。
from django.views.generic.edit import CreateView
from .forms import SampleFormModel
from django.urls import reverse, reverse_lazy
class SampleCreateModelForm(CreateView):
template_name = "app/sample_create.html"
form_class = SampleFormModel
success_url = reverse_lazy("app/sample_create")
urls.py
pj/urls.pyでは、トップページにアクセスがあった際、appのurls.pyに飛ぶように設定します。
app/urls.pyでは、トップページにアクセスがあった際、views.pyで定義したビュー関数(SampleCreateModelForm)とテンプレート(sample_create)を紐づけてブラウザに返すように設定します。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('app.urls')),
path('admin/', admin.site.urls),
]
from django.urls import path
from . import views
urlpatterns = [
path('', views.SampleCreateModelForm.as_view(), name='app/sample_create'),
]
テンプレート(templates)
ビュー関数から引き渡されるフォームを反映させることがポイントです。ポイントは下記の通りです。
・POSTメソッドでフォームを作成すること。
・{% csrf_token %}タグを忘れず付けること。
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
</head>
<body>
{% block main %}
{% endblock %}
</body>
</html>
{% extends 'app/base.html' %}
{% block main %}
<div class="container my-3">
<div class="text-center my-3">
<h2>新しい日記を作成</h2>
</div>
<form method="POST"> {% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary form-control" type="submit">登録</button>
</form>
</div>
{% endblock %}
admin.py
最後に、管理画面で登録したデータを確認できるように、下記コマンドを追加します。
from django.contrib import admin
from .models import *
admin.site.register(SampleModel)
マイグレーションとスーパーユーザーの作成
モデルを定義しましたのでマイグレーションの必要があります。ターミナルから下記コマンドを実行して下さい。
# cwd : pj
python manage.py makemigrations
python manage.py migrate
# cwd : pj
python manage.py createsuperuser
# 実行結果
System check identified some issues:
Username (leave blank to use 'username'): admin # <=今回は「admin」をユーザー名に登録しました。
Email address: # <=ブランクのままエンターで大丈夫です。
Password: # <=任意のパスワードを入力します。後程、管理画面からログインする際に必要となりますので忘れないようにご注意下さい。
Password (again):
データ入力と確認
いよいよ、ブラウザを立ち上げてデータ入力していきます。まずは、開発用サーバーを下記コマンドで立ち上げます。
# cwd : pj
python manage.py runserver
ブラウザが立ち上がると下記のような投稿フォームが表示されます。
ここで、タイトルと本文にテキストを入力して、登録ボタンをクリックします。

下記のように、URL入力欄の末尾に”/admin”を追加してクリックすると管理画面へ遷移します。

管理画面のトップページにアクセスしたら、先程作成したユーザー名とパスワードを入力してログインします。

ログイン後の画面でアプリケーション欄に下記のように登録されていれば、登録成功です。

Sample modelsをクリックすると投稿した日記が確認できます。


以上となります。お疲れ様でした。
コメント