Django#3 ModelとForm~モデルを作成してフォームからデータを登録しよう~
スポンサーリンク

Model

Modelとは?

動的なウェブサイトではデータベースが欠かせません。Djangoではデータベースとしてモデルを使用します。

テーブル作成

まずはテーブルを作成します。Djangoではmodelクラスを利用してテーブルを作成することができます。

重要な点
  • Djangoのモデルではテーブルを定義するとテーブルが作成される
  • IDは自動で作成される

MySQLで実装したい人

MySQLで実装したい人は事前に以下のページを参考にMySQLの設定をしてください。

①テーブルを定義

いきなりではありますが、リレーショナルデータベースを作成していきます。今回はForeignKeyを利用した公式ドキュメントの内容を参考にしていきたいと思います。

from django.db import models


class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

    def __str__(self):
        return self.first_name


class Album(models.Model):
    artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

    def __str__(self):
        return self.name
②設定の追加

Djangoにアプリを利用することを教える必要があります。そのために、settings.pyにアプリを設定します。

###settings.py
# Application definition

INSTALLED_APPS = [
    '{アプリ名}.apps.MyappConfig',#  ←
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
③初回に実行するmakemigrations

DjangoではModelはバージョン管理されています。Modelを作成したり変更した場合はMigrationをする必要があります

Migrationをすることでテーブルマップのスクリプトが作成されます。

モデルを作成して、設定も追加したら、ミグレーションを行う必要があります。

公式ドキュメントでは「django-admin」を利用する方法が記述されていますが、私はwindows11のPCで以下のコードで実施しました。

py .\manage.py makemigrations
④migrate

モデルを定義したら必ずmigrateを実行します。これらを実行することで、マップのファイルが作成されて、モデルとデータベースが紐づきます。

こちらも公式ドキュメントでは「django-admin」を利用する方法が記述されていますが、私はwindows11のPCで以下のコードで実施しました。

py .\manage.py migrate
履歴の確認:showmigrations

以下でミグレーションの履歴を確認することができます。

py .\manage.py showmigrations
⑤adminにモデルを登録

adminにモデルを追加して管理できるようにします。

from django.contrib import admin
from .models import Musician, Album

# Register your models here.
admin.site.register(Musician)
admin.site.register(Album)

Form

ここまでで作成したモデルにデータを格納していくためのフォームを作成していきたいと思います。

①forms.pyを作成

アプリケーションのディレクトリ内にforms.pyを作成して格納します。

②Modelを利用してFormを作成

forms.pyでDjangのformsクラスとmodels.pyで定義したモデルをインポートします。

インポートしたらModelFormを作成します。

# フォームのクラスをインポート
from django import forms
# モデルをインポート
from .models import Musician, Album

# Musicialモデルを利用したMusicialFormを作成
class MusicianForm(forms.ModelForm):
    class Meta:
        # モデルはMusicialを使用
        model = Musician
        # フィールドはすべてを利用
        fields = '__all__'
        ##  みぎでもOK → fields = ["first_name", "last_name", "instrument"]
③views.pyでフォームを読み込みモデルへ保存する

views.pyでフォームを読み込みHTMLへ表示します。

フォームで入力されPOSTを受信した場合はデータが有効か確認をして問題なければデータを保存します。

### views.py
from django.shortcuts import render, redirect

# フォームをインポート
from myapp.forms import MusicianForm

# Create your views here.
def home(request):
    # フォームを作成
    form = MusicianForm()
    # メソッドがPOSTだった場合
    if request.method == "POST":
        # POSTデータを取得
        form = MusicianForm(request.POST)
        # データが有効か確認
        if form.is_valid():
            # 有効であればデータを格納
            form.save()
            # ページを再読込する
            return redirect('home')
    # HTMLで読み込むformを定義
    context = {"form": form}
    return render(request, "home.html", context)
④HTMLを作成

アプリフォルダにtemplatesディレクトリを作成して、「home.html」を作成します。

html内フォームに{{form}}を設置するとforms.pyで作成したフォームが設置されます。

{% csrf_token %}はクロスサイトリクエストフォージェリ用のトークンでセキュリティ対策で必要なものになります。

<!-- templates内のhome.html -->
<!DOCTYPE html>
<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>Document</title>
</head>
<body>
  <form action="" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <button type="submit" value="submit">送信</button>
  </form>
</body>
</html>
⑤urls.pyへ設定

urls.pyで作成したviewの設定を入れれば完了です。

from django.urls import path, include
from . import views

urlpatterns = [
    path('', views.home, name='home'),
]

付録:モデルのデータを取得

・{モデル名}.objects.all()ですべてのデータを取得します

 *事前にモデルをインポートしておきます

・HTMLでは{% for %}文を使って表現することができます

### views.py
from django.shortcuts import render, redirect

# フォームをインポート
from .froms import MusicianForm
# モデルをインポート
from .models import Musician, Album

# Create your views here.
def home(request):
    # フォームを作成
    form = MusicianForm()
    # メソッドがPOSTだった場合
    if request.method == "POST":
        # POSTデータを取得
        form = MusicianForm(request.POST)
        # データが有効か確認
        if form.is_valid():
            # 有効であればデータを格納
            form.save()
            # ページを再読込する
            return redirect('home')
    objects = Musician.objects.all()
    # HTMLで読み込むformを定義
    context = {"form": form,
               "objects": objects}
    return render(request, "home.html", context)
<!-- templates内のhome.html -->
<!DOCTYPE html>
<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>Document</title>
</head>
<body>
  <form action="" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <button type="submit" value="submit">送信</button>
  </form>
  <table>
    <tr>
      <td>first name</td>
      <td>last name</td>
      <td>instrument</td>
    </tr>
      {% for object in objects %}
      <tr>
        <td>{{object.first_name}}</td>
        <td>{{object.last_name}}</td>
        <td>{{object.instrument}}</td>
      </tr>
      {% endfor %}
    </tr>
  </table>
</body>
</html>

付録:CSSを読み込む

・templatesと同じディレクトリに「static」を作成

・staticの中に「css/style.css」を作成

・{% load static %}をHTMLの先頭へ

・<link rel="stylesheet" href="{% static 'css/style.css' %}">を作成

<!-- templates内のhome.html -->
{% load static %}
<!DOCTYPE html>
<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">
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
  <title>Document</title>
</head>
<body>
  <form action="" method="post">
    {% csrf_token %}
    {{form.as_p}}
    <button type="submit" value="submit">送信</button>
  </form>
  <table>
    <tr>
      <td>ID</td>
      <td>first name</td>
      <td>last name</td>
      <td>instrument</td>
    </tr>
      {% for object in objects %}
      <tr>
        <td>{{object.id}}</td>
        <td>{{object.first_name}}</td>
        <td>{{object.last_name}}</td>
        <td>{{object.instrument}}</td>
      </tr>
      {% endfor %}
    </tr>
  </table>
</body>
</html>

テーブルのおまけ

テーブルを定義

<Django>

from django.db import models

class Users(models.Model):
	first_name = models.CharField(max_length=30)
	last_name = models.CharField(max_length=30)
データ追加

<SQL>

SELECT * FROM users WHERE id = 1;

<Django>

user = Users.objects.get(id=1)
データ取得

<SQL>

UPDATE user
SET last_name = "Ken"
WHERE id = 1;

<Django>

user = Users.object.get(id=1)
user.last_name = "Ken"
user.save()
データ追加

<SQL>

INSERT INTO users(id, first_name, last_name)
VALUES (1, "Vyn", "Sen")

<Django>

new_user = Users(id=1, "Vyn", "Sen")
new_user.save()
データ削除

<SQL>

DELETE FROM users WHERE id = 1;

<Django>

Users.objects.filter(id=1).delete()

migrationのおまけ

<Terminal>

python manage.py showmigrations

<Terminal>

python manage.py migrate myapp1 0001
# myapp1 ▶︎ アプリ名
# 0001 ▶︎ バージョン番号

<Terminal>

python manage.py shell

<Terminal>

from myapp1.models import Menu

<Terminal>

Menu.objects.all()

<Terminal>

python manage.py showmigrations

Foreign Keyの連携

Foreign Keyの連携を見ていきたいと思います。まず、モデルを作成します。

作成したモデルをアドミンへ設定します。

models.pyの作成

from django.db import models

# Create your models here.
class Category(models.Model):
  category =models.CharField(max_length=200)

class Users(models.Model):
  username = models.CharField(max_length = 100)
  email = models.CharField(max_length = 100)
  category_id = models.ForeignKey(Category, on_delete=models.PROTECT, default=None, related_name="category_name")

  def __str__(self):
    return self.u_name

admin.py

from django.contrib import admin
from .models import Category, Users

# Register your models here.
admin.site.register(Category)
admin.site.register(Users)

ぜひ参考にしてください!また!