ホーム >  Python > Django >  Django Modelsを使ってデータを登録する


Posted:2017/10/18 10:08:45 AM|Category : Django

Django Modelsを使ってデータを登録する

Anaconda・Django1.11.3環境に、Modelsを使って、フォームに入力したデータを登録します。

Modelとは?

Modelは、サイトを構成するデータソース(主にデータベース)へのアクセスを請け負います。理解するにはデータベースの知識も必要になるため、Djangoでの難所です。

CRUD

難所ですが、以下のシンプルなCRUDのルールを覚えれば実現可能です。CRUDができれば、一般的なWebアプリケーションは開発できます。

  • Create(生成)
  • Read(読み取り)
  • Update(更新)
  • Delete(削除)

基礎知識とModelクラス(理論)

データベースにテーブルを作るDDL(Data Definition Language)は、以下のようになります。

CREATE TABLE "テーブル名" (
   カラム1 データ型 {その他の制約},
   カラム2 データ型 {その他の制約},
);

以下の表が、DDLとModelクラスがどのように紐づくかの関係図です。Modelクラスの場合も、データベースのDDLと同じ情報を持ちます。

DDL Modelクラス
テーブル名 クラス名
カラム名 クラス変数名
データ型 クラス変数に代入するオブジェクト(Fieldクラスのインスタンス)
その他 Fieldクラスのオプション

この情報を元にした、Modelクラスの雛形は以下の通りです。

class テーブル名(Model):
    カラム名1 = データ型(その他の制約)
    カラム名2 = データ型(その他の制約)

実例

※ここで出てくるコードはあくまで実例なので、実際に書く必要はありません。

テーブル定義

論理名 物理名
顧客テーブル customer

論理名 物理名 データ型 長さ 必須 キー 外部キー 備考
ID id INT YES PK AUTO INCREMENT
last_name varchar 20 YES
last_name varchar 20 YES
Eメールアドレス email_address varchar 255 YES UK
メモ memo text

DDL

CREATE TABLE customer (
   id serial NOT NULL PRIMARY KEY,
   last_name varchar(20) NOT NULL,
   first_name varchar(20) NOT NULL,
   email_address varchar(255) NOT NULL UNIQUE,
   memo text
);

Model

※ここで出てくるコードはあくまで実例なので、実際に書く必要はありません。

Fieldクラスのオプションに何も指定しなければ、NOT NULL制約がかかります。PRIMARY KEYとなるクラス変数を定義しない場合、idが自動的に定義されます。

from django.core.db import models

class Customer(models.Model):
    # id = AutoField(primary_key=True)  # 自動的に追加されるので定義不要
    last_name = CharField(max_length=20)
    first_name = CharField(max_length=20)
    email_address = EmailField(max_length=255, unique=True)
    memo = TextField(null=True)

※Modelでは、幾つかの制約が暗黙的に定義されています。

migrateを実行

migrateとは、Modelクラスを定義したり、定義後のModelクラスに変更を加えたときに、 それらをデータベースのスキーマに反映するコマンドです。Djangoでは、migrateの履歴管理や一部のモジュールでデータベースを使います。

通常は、settings.pyにDBの設定を行った直後にmigrateを実施します。

  • プロジェクトを作る( djang-admin.py startproject XXXXXX )
  • settings.py にDBの設定を書く(DBAにsqlite3を使う場合は、この手順を省略する)
  • migrateを実行する ( python manage.py migrate )
python projectname/manage.py migrate

環境

OS CentOS 7.1.1503
pyenv 1.1.3-5-g7dae197
Anaconda 3-4.3.0
MariaDB 5.5.52-1.el7
Apache 2.4.6
mod_wsgi 4.5.14
Django 1.11.3

Modelクラスを定義する

実際にModelクラスをmodels.pyに追加します。機能としましては、画面から投稿されたデータ検証し、検証結果に問題が無いデータをデータベースに保存するためのModelとします。

①models.pyに「Hello」モデルを記述します。

from django.db import models


class Hello(models.Model):
    your_name = models.CharField(max_length=10)

    def __str__(self):
        return "<{0}>".format(self.your_name)

②Modelクラスをデータベースのスキーマに反映します。

Modelクラスをデータベースのスキーマに反映するには、2つの手順をふみます。

  • データベースのスキーマとModelクラスの差を取り、変更処理が書かれているPythonファイルを生成する
  • 変更処理が書かれているPythonファイルを使いデータベースのスキーマを変更する

※それぞれ manage.py で実行できます。

python manage.py makemigrations
python manage.py migrate

Django ShellでModelを使う

実際にModelをDjango shellからModelを操作してCRUDの基礎を学びます。Django shellからModelを操作します。

①Django shellを起動します。プロジェクト名を「pj1」とします。アプリケーション名を「app1」とします。

python pj1/manage.py shell

②データを登録します。

>>> from app1.models import Hello
>>> kenji = Hello.objects.create(your_name='Kenji')
>>> print("id:{0}, your_name:{1}".format(kenji.id, kenji.your_name))
id:1, your_name:Kenji
>>> takuya = Hello.objects.create(your_name='Takuya')
>>> print("id:{0}, your_name:{1}".format(takuya.id, takuya.your_name))
id:2, your_name:Takuya

③データを全件取得します。Hello.objects.all() で、無条件ですべてのデータを取得できます。

>>> Hello.objects.all()
[<Hello: <Kenji>>, <Hello: <Takuya>>]
>>> for h in Hello.objects.all(): print(h.your_name)
...
Kenji
Takuya

④idを指定して検索する場合など、必ず1件しかデータが取得できない場合、Hello.objects.get({パラメーター}) で検索します。

>>> h = Hello.objects.get(pk=1)
>>> print(h.your_name)
Kenji

⑤条件に一致するデータを検索する場合、Hello.objects.filter({パラメーター}) で検索します。

>>> h_qs = Hello.objects.filter(id__in=[1,2])
>>> for h in h_qs: print(h.your_name)
...
Kenji
Takuya
>>> for h in h_qs.filter(your_name='Kenji'): print(h.your_name)
...
Kenji

⑥データを更新します。インスタンス変数を上書きした後、XXX.save() メソッドを呼び出します。

>>> h = Hello.objects.get(pk=1)
>>> print(h.your_name)
Kenji
>>> h.your_name = 'Makoto'
>>> h.save()
>>> h = Hello.objects.get(pk=1)
>>> print(h.your_name)
Makoto

⑦データを削除します。データを更新する場合は、インスタンス変数を上書きした後、XXX.delete() メソッドを呼び出します。

>>> h = Hello.objects.get(pk=1)
>>> h.delete()
>>> h = Hello.objects.get(pk=1)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/eiry/PycharmProjects/practice/venv/lib/python3.4/site-packages/django/db/models/manager.py", line 127, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/eiry/PycharmProjects/practice/venv/lib/python3.4/site-packages/django/db/models/query.py", line 334, in get
    self.model._meta.object_name
hello.models.DoesNotExist: Hello matching query does not exist.

画面から入力されたデータをデータベースに保存

画面から入力されたデータを、Modelを使ってデータベースに保存します。

①forms.pyにHelloFormフォームを追加します。

vi pj1/app1/forms.py

以下のように編集します。

from django import forms

class HelloForm(forms.Form):
    your_name = forms.CharField(
        label = '名前',
        max_length = 20,
        required=True,
        widget=forms.TextInput()
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['your_name'].widget.attrs['class'] = 'form-control'

②views.pyにビュー関数を追加します。

vi pj1/app1/views.py

以下のように編集します。

from django.shortcuts import redirect
from . import forms, models

def hello_models(request):
    form  = HelloForm(request.POST or None)
    if form.is_valid():
        models.Hello.objects.create(**form.cleaned_data)
        return redirect('app1:index')

    d = {
        'form' : form,
        'hello_qs': models.Hello.objects.all().order_by('-id'),
    }
    return render(request, 'models.html', d)

redirect(‘app1:index’)

redirect関数の引数には、「namespace:name」と書くことでURLConfから必要なURLを逆引きします。また、「URL:http://XXXXXX」を直接書くこともできます。

PRGパターン

ビュー関数の中で「redirect(….)」と言う関数を呼び出していますが、これがPRGパターンのR(Redirect)に該当するところです。

③templatesディレクトリにmodels.htmlを追加します。

vi pj1/app1/templates/models.html

以下のように編集します。base.htmlは以前の記事を参照して下さい。

{% extends "base.html" %}

{% block content %}
<div class="container">
  {{ message }}

  <h1>your_nameを登録する</h1>
  <h2>登録</h2>
  <form method="post" action="">
    <div class="form-group">
    {{ form.errors.your_name }}
    <label>{{ form.your_name.label }} {{ form.your_name }}</label><br>
    <input type="submit" class="btn btn-primary" value="送信">
    {% csrf_token %}
   </div>
  </form>
  <hr>
  <h2>一覧</h2>
  {% for h in hello_qs %}
    {{ h.your_name }}<br>
  {% endfor %}
</div>
{% endblock %}

クロスサイトリクエスト・フォージェリ

Djangoは、この攻撃に対抗する手段としてPOST時に暗号論的擬似乱数値をHIDDENに埋め込む方法が採用されています。 テンプレートの中で「{% csrf_token %}」と言う記述がHIDDENに暗号論的擬似乱数値を埋め込んでいる所です。 これを記述しないと、POST時にセキュリティーエラーが発生します。

④最後にURLConfを書きます。

vi pj1/app1/urls.py

以下のように編集します。

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
・・・(省略)・・・・
    url(r'^models/$', views.hello_models, name="hello_models"),
]

⑤簡易Webサーバを立ち上げます。

python pj1/manage.py runserver 0.0.0.0:8000

⑥ホスト環境のブラウザから、以下のURLを入力します。

http://localhost:8000/models/

⑦動作確認します。入力フォームに名前を入力して送信ボタンを押すと、your_nameに情報が登録されます。

画面を表示したとき エラーが発生せず、画面が表示できることを確認します。
名前に何も入力しない場合 「このフィールドは必須です。」と言うメッセージが表示されることを確認します。
名前に「テスト名」と入力した場合 『一覧』の下に「テスト名」と表示されることを確認します。

トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 2008年04月 金融機関系I

最近の投稿
人気記事
カテゴリー
広告