Djangoのハイライト:モデル、管理、およびリレーショナルデータベースの活用(パート3)

公開: 2022-03-10
クイックサマリー↬管理パネルは、Django Webフレームワークが提供する最も強力で柔軟な機能の1つであり、すぐに使える機能と無限のカスタマイズを組み合わせています。 ライブラリインベントリシステムに基づくサンプルプロジェクトを使用して、管理パネルを使用して、モデルの作成とDjangoでのリレーショナルデータベースの操作について学習します。

始める前に、Djangoの組み込みの管理機能は、カスタマイズした後でも、エンドユーザー向けではないことに注意してください。 管理パネルは、ソフトウェアを作成および保守するための開発者、オペレーター、および管理者ツールとして存在します。 開発するプラットフォーム上でエンドユーザーにモデレート機能やその他の管理者機能を提供するために使用することを意図したものではありません。

この記事は、2つの部分の仮説に基づいています。

  1. Django管理パネルは非常に直感的であるため、基本的にはその使用方法をすでに知っています。
  2. Django管理パネルは非常に強力なので、Djangoモデルを使用してリレーショナルデータベースのデータを表現する方法を学ぶためのツールとして使用できます。

これらのアイデアには、管理パネルのより強力な機能をアクティブ化するための構成コードを作成する必要があり、データの表現を指定するためにDjangoのモデルベースのORM(オブジェクトリレーショナルマッピング)を使用する必要があることに注意してください。私たちのシステムで。

おすすめの読み物

「DjangoHighlights」は、DjangoでのWeb開発の重要な概念を紹介するシリーズです。 安全なユーザー認証フローの提供について読み、複雑なページを作成するためのDjangoテンプレートの使用に関するデモンストレーションをフォローすることをお勧めします。

ジャンプした後もっと! 以下を読み続けてください↓

セットアップ

この記事では、サンプルプロジェクトを使用します。 このプロジェクトは、図書館がその本や常連客について保存するデータをモデル化しています。 この例は、ユーザーや在庫を管理する多くのタイプのシステムにかなり適用できるはずです。 データがどのように見えるかを簡単に確認します。

データ・モデル。 (大プレビュー)

サンプルコードをローカルマシンで実行するには、次の手順を実行してください。

1.パッケージのインストール

Python 3.6以降がインストールされている場合は、ディレクトリと仮想環境を作成します。 次に、次のパッケージをインストールします。

 pip install django django-grappelli

Djangoは、この記事で使用しているWebフレームワークです。 ( django-grappelliは、簡単に説明する管理パネルのテーマです。)

2.プロジェクトの取得

以前のパッケージをインストールした状態で、GitHubからサンプルコードをダウンロードします。 走る:

 git clone https://github.com/philipkiely/library_records.git cd library_records/library

3.スーパーユーザーの作成

次のコマンドを使用して、データベースをセットアップし、スーパーユーザーを作成します。 コマンドラインインターフェイスは、スーパーユーザーを作成するプロセスを順を追って説明します。 スーパーユーザーアカウントは、すぐに管理パネルにアクセスする方法になるため、設定したパスワードを忘れないでください。 使用する:

 python manage.py migrate python manage.py createsuperuser

4.データのロード

調査のために、データベースにロードできるフィクスチャと呼ばれるデータセットを作成しました(フィクスチャの作成方法の詳細については、記事の最後を参照してください)。 管理パネルでデータベースを探索する前に、フィクスチャを使用してデータベースにデータを入力します。 走る:

 python manage.py loaddata ../fixture.json

5.サンプルプロジェクトの実行

これで、サンプルコードを実行する準備が整いました。 サーバーを実行するには、次のコマンドを使用します。

 python manage.py runserver

ブラウザを開いてhttps://127.0.0.1:8000にアクセスし、プロジェクトを表示します。 / admin /の管理パネルに自動的にリダイレクトされることに注意してください。 私はlibrary / urls.pyの次の設定でそれを達成しました:

 from django.contrib import admin from django.urls import path from records import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index), ]

records / views.pyで次の単純なリダイレクトと組み合わせる:

 from django.http import HttpResponseRedirect def index(request): return HttpResponseRedirect('/admin/')

管理パネルの使用

できました! ページを読み込むと、次のように表示されます。

Django管理パネルのメインページ。 (大プレビュー)

このビューは、 records /admin.pyの次の定型コードで実現されます。

 from django.contrib import admin from .models import Book, Patron, Copy admin.site.register(Book) admin.site.register(Copy) admin.site.register(Patron)

このビューにより、システムが保存するデータを最初に理解できるはずです。 謎のいくつかを取り除きます。 GroupsUsersはDjangoによって定義され、システム上のアカウントの情報と権限を保存します。 Userモデルの詳細については、このシリーズの以前の記事を参照してください。 BooksCopys 、およびPatronsは、移行の実行時に作成し、フィクスチャをロードすることによって入力されたデータベース内のテーブルです。 Djangoは、スペルが間違っている「コピー」のような場合でも、「s」を追加することでモデル名を単純に複数形にすることに注意してください。

データ・モデル。 (大プレビュー)

私たちのプロジェクトでは、 Bookは、タイトル、著者、発行日、およびISBN(国際標準図書番号)を含むレコードです。 ライブラリは、各BookCopy 、または場合によっては複数の本を保持します。 各Copyは、 Patronがチェックアウトすることも、現在チェックインすることもできます。 Patronは、ユーザーの住所と生年月日を記録するUserの拡張機能です。

作成、読み取り、更新、破棄

管理パネルの標準機能の1つは、各モデルのインスタンスを追加することです。 「本」をクリックしてモデルのページに移動し、右上隅にある「本を追加」ボタンをクリックします。 そうすることで、フォームが表示されます。フォームに入力して保存すると、本を作成できます。

本を作成する(大プレビュー)

Patronを作成すると、管理者の作成フォームの別の組み込み機能が明らかになります。同じフォームから直接接続モデルを作成できます。 以下のスクリーンショットは、 Userドロップダウンの右側にある緑色のプラス記号によってトリガーされるポップアップを示しています。 したがって、同じ管理ページで両方のモデルを作成できます。

パトロンを作成します。 (大プレビュー)

同じメカニズムでCOPYを作成できます。

各レコードについて、行をクリックして同じフォームを使用して編集できます。 管理アクションを使用してレコードを削除することもできます。

管理者のアクション

管理パネルの組み込み機能は広く役立ちますが、管理アクションを使用して独自のツールを作成できます。 2つ作成します。1つは本のコピーを作成するためのもので、もう1つは図書館に返却された本をチェックインするためのものです。

BookCopyを作成するには、URL /admin/records/book/に移動し、[アクション]ドロップダウンメニューを使用して[書籍のコピーを追加]を選択し、左側の列のチェックボックスを使用しますインベントリにコピーを追加する1つまたは複数の本を選択するためのテーブルの。

コピーアクションを作成します。 (大プレビュー)

これを作成するには、後で説明するモデルメソッドに依存します。 records / admin.pyに次のようにProfileモデルのModelAdminクラスを作成することで、これを管理アクションとして呼び出すことができます。

 from django.contrib import admin from .models import Book, Patron, Copy class BookAdmin(admin.ModelAdmin): list_display = ("title", "author", "published") actions = ["make_copys"] def make_copys(self, request, queryset): for q in queryset: q.make_copy() self.message_user(request, "copy(s) created") make_copys.short_description = "Add a copy of book(s)" admin.site.register(Book, BookAdmin)

list_displayプロパティは、モデルの概要ページでモデルを表すために使用されるフィールドを示します。 actionsプロパティは、管理アクションを一覧表示します。 管理アクションはBookAdmin内の関数として定義され、管理オブジェクト自体、リクエスト(クライアントから送信される実際のHTTPリクエスト)、クエリセット(チェックボックスがオンになっているオブジェクトのリスト)の3つの引数を取ります。 クエリセット内の各アイテムに対して同じアクションを実行してから、アクションが完了したことをユーザーに通知します。 ドロップダウンメニューで正しく識別できるように、すべての管理アクションには簡単な説明が必要です。 最後に、モデルを登録するときにBookAdminを追加します。

プロパティを一括で設定するための管理アクションの記述は、かなり繰り返します。 Copyをチェックインするためのコードは次のとおりです。前のアクションとほぼ同等であることに注意してください。

 from django.contrib import admin from .models import Book, Patron, Copy class CopyAdmin(admin.ModelAdmin): actions = ["check_in_copys"] def check_in_copys(self, request, queryset): for q in queryset: q.check_in() self.message_user(request, "copy(s) checked in") check_in_copys.short_description = "Check in copy(s)" admin.site.register(Copy, CopyAdmin)

管理テーマ

デフォルトでは、Djangoは管理パネルにかなりシンプルなスタイルを提供します。 独自のテーマを作成することも、サードパーティのテーマを使用して管理パネルの外観を新しくすることもできます。 人気のあるオープンソーステーマの1つは、この記事の前半でインストールしたgrappelliです。 その全機能については、ドキュメントを確認してください。

テーマのインストールは非常に簡単で、2行しか必要ありません。 まず、 library / settings.pyの次のように、 grappelliINSTALLED_APPSに追加します。

 INSTALLED_APPS = [ 'grappelli', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'records', ]

次に、 library / urls.pyを調整します:

 from django.contrib import admin from django.urls import path, include from records import views urlpatterns = [ path('grappelli/', include('grappelli.urls')), path('admin/', admin.site.urls), path('', views.index), ]

これらの変更を行うと、管理パネルは次のようになります。

テーマのある管理パネル。 (大プレビュー)

そこには他にもたくさんのテーマがあり、またあなたはあなた自身のものを開発することができます。 この記事の残りの部分では、デフォルトの外観を維持します。

モデルを理解する

管理パネルに慣れ、それを使用してデータをナビゲートできるようになったので、データベース構造を定義するモデルを見てみましょう。 各モデルは、リレーショナルデータベース内の1つのテーブルを表します。

リレーショナルデータベースは、データを1つ以上のテーブルに格納します。 これらの各テーブルには、主キー(各要素の一意の識別子)と、文字列、整数、日付などのさまざまなタイプの値の1つ以上の列を含む、指定された列構造があります。 データベースに格納されている各オブジェクトは、単一の行として表されます。 名前の「リレーショナル」部分は、おそらくテクノロジーの最も重要な機能であるテーブル間の関係の作成に由来しています。 オブジェクト(行)は、1対1、1対多(外部キー)、または他のテーブルの行への多対多のマッピングを持つことができます。 これについては、例でさらに説明します。

Djangoは、デフォルトで、開発にSQLite3を使用します。 SQLite3は単純なリレーショナルデータベースエンジンであり、 python manage.py migrateを初めて実行したときにデータベースがdb.sqlite3として自動的に作成されます。 この記事ではSQLite3を継続しますが、主に同時ユーザーで上書きが発生する可能性があるため、本番環境での使用には適していません。 本番環境で、またはいつかデプロイする予定のシステムを作成する場合は、PostgreSQLまたはMySQLを使用してください。

Djangoは、モデルを使用してデータベースとのインターフェースを取ります。 DjangoのORMの一部を使用して、 records / models.pyファイルには複数のモデルが含まれ、各オブジェクトのフィールド、プロパティ、およびメソッドを指定できます。 モデルを作成するときは、合理的な範囲内で「ファットモデル」アーキテクチャを目指します。 つまり、データの検証、解析、処理、ビジネスロジック、例外処理、エッジケースの解決、および同様のタスクのできるだけ多くを、モデル自体の仕様で処理する必要があります。 内部的には、Djangoモデルは非常に複雑で機能的なオブジェクトであり、広く役立つデフォルトの動作を備えています。 これにより、大量のコードを記述しなくても、「ファットモデル」アーキテクチャを簡単に実現できます。

サンプルアプリケーションの3つのモデルを見ていきましょう。 これは紹介記事であり、Djangoフレームワークの完全なドキュメントではないため、すべてを網羅することはできませんが、これらの単純なモデルを構築する際に行った最も重要な選択を強調します。

Bookクラスは、モデルの中で最も単純です。 これはrecords / models.pyからのものです:

 from django.db import models class Book(models.Model): title = models.CharField(max_length=300) author = models.CharField(max_length=150) published = models.DateField() isbn = models.IntegerField(unique=True) def __str__(self): return self.title + " by " + self.author def make_copy(self): Copy.objects.create(book=self)

すべてのCharFieldフィールドには、指定されたmax_length属性が必要です。 従来の長さは150文字で、非常に長いタイトルの場合はtitleを2倍にしました。 もちろん、それでも任意の制限があり、それを超える可能性があります。 無制限のテキスト長の場合は、 TextFieldを使用します。 publishedたフィールドはDateFieldです。 本が出版された時期は関係ありませんが、出版された場合は、 DateTimeFieldを使用します。 最後に、ISBNは整数であり(ISBNは10桁または13桁であるため、すべて整数の最大値内に収まります)、2冊の本が同じISBNを持つことはできないため、 unique=Trueを使用します。これは、データベースレベルで適用されます。

すべてのオブジェクトには、文字列表現を定義するメソッド__str__(self)があります。 models.Modelクラスによって提供されるデフォルトの実装をオーバーライドし、代わりに、モデルが文字列として表されるすべての場所で「著者によるタイトル」として本を表します。 以前、 Bookの管理オブジェクトでlist_displayを使用して、管理パネルのリストに表示されるフィールドを決定したことを思い出してください。 そのlist_displayが存在しない場合、管理者リストには、 PatronCopyの両方の場合と同様に、代わりにモデルの文字列表現が表示されます。

最後に、以前に作成した管理アクションで呼び出したBookのメソッドがあります。 この関数は、データベース内のBookの特定のインスタンスに関連するCopyを作成します。

Patronに移ると、このモデルでは1対1の関係の概念が導入されています。この場合は、組み込みのUserモデルが使用されています。 records / models.pyからチェックしてください:

 from django.db import models from django.contrib.auth.models import User class Patron(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) address = models.CharField(max_length=150) dob = models.DateField() def __str__(self): return self.user.username

userフィールドは、正確には全単射関数ではありません。 Patronインスタンスが関連付けられていないUserインスタンスが存在する可能性があります。 ただし、 Userを複数のPatronインスタンスに関連付けることはできません。また、 Patronは、ユーザーとの関係が1つだけでなければ存在できません。 これはデータベースレベルで実施され、 on_delete=models.CASCADE仕様によって保証されます。 Userインスタンスが削除されると、関連するProfileが削除されます。

以前に見た他のフィールドと__str__(self)関数。 モデルの関数で属性(この場合はuser.username )を取得するために、1対1の関係を介して到達できることは注目に値します。

データベースリレーションの有用性を拡張するために、 records /models.pyからのCopyに注目しましょう。

 from django.db import models class Copy(models.Model): book = models.ForeignKey(Book, on_delete=models.CASCADE) out_to = models.ForeignKey(Patron, blank=True, null=True, on_delete=models.SET_NULL) def __str__(self): has_copy = "checked in" if self.out_to: has_copy = self.out_to.user.username return self.book.title + " -> " + has_copy def check_out(self, p): self.out_to = p self.save() def check_in(self): self.out_to = None self.save()

繰り返しになりますが、これまでにほとんどのことを見てきましたので、新しいものに焦点を当てましょう: models.ForeignKeyCopyは単一のBookである必要がありますが、ライブラリには各Bookの複数のCopyが含まれる場合があります。 Bookは、ライブラリのカタログにCopyがなくてもデータベースに存在できますが、 Copyは、基になるBookなしでは存在できません。

この複雑な関係は、次の行で表されます。

 book = models.ForeignKey(Book, on_delete=models.CASCADE)

削除動作は、 Userに関するPatronの動作と同じです。

CopyPatronの関係は少し異なります。 Copyは最大1人のPatronにチェックアウトできますが、各Patronはライブラリで許可されている数のCopyをチェックアウトできます。 ただし、これは永続的な関係ではなく、 Copyがチェックアウトされない場合があります。 PatronCopyは、データベース内で互いに独立して存在します。 一方のインスタンスを削除しても、もう一方のインスタンスは削除されません。

この関係は依然として外部キーのユースケースですが、引数が異なります。

 out_to = models.ForeignKey(Patron, blank=True, null=True, on_delete=models.SET_NULL)

ここで、 blank=Trueを指定すると、フォームはリレーションの値としてNoneを受け入れることができ、 null=Trueを指定すると、データベース内のCopyのテーブルのPatronリレーションの列がnullを値として受け入れることができます。 Copyがチェックアウトされている間にPatronインスタンスが削除された場合にCopyでトリガーされる削除動作は、 Patronフィールドをnullに設定することにより、 Copyをそのままにして関係を切断することです。

同じフィールドタイプmodels.ForeignKeyは、オブジェクト間の非常に異なる関係を表現できます。 この例にうまく当てはまらなかった1つの関係は、多対多のフィールドです。これは、1対1のフィールドに似ていますが、名前からわかるように、各インスタンスを他の多くのインスタンスに関連付けることができます。そして、1冊の本に複数の著者がいて、それぞれが複数の本を書いているように、他のすべての人とそれらのそれぞれを他の多くの人と関連付けることができます。

移行

モデルで何が表現されているかをデータベースがどのように認識しているか疑問に思われるかもしれません。 私の経験では、移行は、移行が行われなくなるまでは非常に簡単なことの1つであり、その後、移行はあなたの顔を食い尽くします。 初心者向けに、マグカップをそのままにしておく方法は次のとおりです。移行とその操作方法について学びますが、移行ファイルを手動で編集することは避けてください。 自分が何をしているのかをすでに知っている場合は、このセクションをスキップして、自分に合った方法を続けてください。

いずれにせよ、主題の完全な治療のために公式文書をチェックしてください。

移行は、モデルの変更をデータベーススキーマの変更に変換します。 自分で作成する必要はありません。Djangoはpython manage.py makemigrationsコマンドを使用して作成します。 このコマンドは、新しいモデルを作成するとき、または既存のモデルのフィールドを編集するときに実行する必要がありますが、モデルメソッドを作成または編集するときに実行する必要はありません。 移行はチェーンとして存在し、データベーススキーマをエラーなしで編集できるように、それぞれが前の移行を参照することに注意することが重要です。 したがって、プロジェクトで共同作業をしている場合は、バージョン管理で単一の一貫した移行履歴を保持することが重要です。 適用されていない移行がある場合は、サーバーを実行する前にpython manage.py migrateを実行してそれらを適用します。

サンプルプロジェクトは、単一の移行、 records / migrations /0001_initial.pyで配布されます。 繰り返しになりますが、これは編集する必要のない自動生成されたコードなので、ここではコピーしませんが、舞台裏で何が起こっているのかを理解したい場合は、先に進んでそれを見てください。

備品

移行とは異なり、フィクスチャはDjango開発の一般的な側面ではありません。 私はそれらを記事とともにサンプルデータを配布するために使用しますが、それ以外の方法で使用したことはありません。 ただ、先ほど使っていたので、紹介せざるを得ないと思います。

かつて、公式ドキュメントはこのトピックに関して少しスリムです。 全体として、フィクスチャは、私が使用しているJSONを含むさまざまな形式でデータベースからデータをインポートおよびエクスポートする方法であるということを知っておく必要があります。 この機能は主に自動テストなどを支援するために存在し、バックアップシステムやライブデータベースのデータを編集する方法ではありません。 さらに、フィクスチャは移行によって更新されないため、互換性のないスキーマを持つデータベースにフィクスチャを適用しようとすると失敗します。

データベース全体のフィクスチャを生成するには、次のコマンドを実行します。

 python manage.py dumpdata --format json > fixture.json

フィクスチャをロードするには、次を実行します。

 python manage.py loaddata fixture.json

結論

Djangoでモデルを作成することは大きなトピックであり、管理パネルを使用することも別のトピックです。 3,000語で、それぞれを紹介することができました。 うまくいけば、管理パネルを使用することで、モデルがどのように機能し、相互に関連するかを調べるためのより良いインターフェースが提供され、データの独自のリレーショナル表現を実験して開発する自信が持てるようになります。

簡単に開始できる場所を探している場合は、 ProfileのようにUserから継承するLibrarianモデルを追加してみてください。 より多くの課題については、各Copyおよび/またはPatronのチェックアウト履歴を実装してみてください(これを達成する方法はいくつかあります)。

Django Highlightsは、DjangoでのWeb開発の重要な概念を紹介するシリーズです。 各記事は、フロントエンドの開発者と設計者がコードベースの「残りの半分」をより深く理解できるようにすることを目的とした、Django開発の側面へのスタンドアロンガイドとして書かれています。 これらの記事は主に理論と慣習を理解するのに役立つように構成されていますが、Django3.0で記述されたコードサンプルがいくつか含まれています。

参考文献

次の記事とドキュメントに興味があるかもしれません。

  • Djangoのハイライト:ユーザーモデルと認証(パート1)
  • Djangoのハイライト:テンプレートによる保存行(パート2)
  • Djangoのハイライト:静的アセットとメディアファイルのラングリング(パート4)
  • Django管理ドキュメント
  • Djangoモデル
  • Djangoモデルフィールドリファレンス
  • Djangoの移行