一対一の関係とは、あるテーブルの1行が別のテーブルの1つのエンティティにのみ関連付けられることを意味する。例えば、ユーザーは自分の資格情報を記述したいくつかのデータを持っているかもしれません。名前、年齢などのユーザーに関する基本情報はすべて1つのモデルに割り当てることができ、一方、ログイン、パスワード、最終ログイン時刻、ログイン失敗回数などの認証情報は、1つのモデルに割り当てることができます。- を別の機種に変更しました。
from django.db import models
class User(models.Model):
name = models.CharField(max_length=20)
class Account(models.Model):
login = models.CharField(max_length=20)
password = models.CharField(max_length=20)
user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key = True)
この一対一の関係を作るために、models.OneToOneField()型のコンストラクタが使用されます。その最初のパラメータは、エンティティがどのモデルに関連付けられるかを指定します(この場合、関連付けはUserモデルです)。2番目のパラメータ on_delete = models.CASCADE は、関連するメインモデルオブジェクト (User) が削除された場合、現在のモデル (UserAccount) のデータが削除されることを示しています。3番目のパラメータprimary_key = Trueは、外部キー(これを通じてメインモデルに接続される)が同時に主キーとして機能することを意味します。したがって、主キー用に別のフィールドを作成する必要はない。
この移行により、SQLite データベースに以下のテーブルが作成されます。
CREATE TABLE "cb_user" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(20) NOT NULL
)
CREATE TABLE "cb_account" (
"login" varchar(20) NOT NULL,
"password" varchar(20) NOT NULL,
"user_id" bigint NOT NULL PRIMARY KEY REFERENCES "cb_user" ("id") DEFERRABLE INITIALLY DEFERRED
)
Accountモデルのuserプロパティを使って、関連するUserモデルオブジェクトを操作することができます。
# ユーザーを作成する
az = User.objects.create(name="Az")
# Azのユーザーアカウントを作成する
acc = Account.objects.create(login = "az", password="1234", user=az)
# ユーザー名を変更する
acc.user.name = "Smith"
# データベースへの変更を保存する
acc.user.save()
print(f"{acc.user.name}, login: {acc.login}, password: {acc.password}")
# Smith, login: az, password: 1234
しかし、Userモデルを通して、リンクされたAccountオブジェクトにも影響を与えることができます。Userモデルにはnameというプロパティしか明示的に定義されていませんが、一対一の関係では、依存するモデルの関連オブジェクトを指す、依存するモデルの名前を冠した別のプロパティが暗黙のうちに作成されます。したがって、この場合、このプロパティは「アカウント」と呼ばれることになります。
# ユーザーを作成する
tom = User.objects.create(name="Tom")
# ユーザーアカウントを作成する
acc = Account(login = "abc", password="testpwd")
tom.account = acc
tom.account.save()
# 更新データ
tom.account.login = "qwerty"
tom.account.password = "123456"
tom.account.save()
print(f"{tom.name}, login: {tom.account.login}, password: {tom.account.password}")
# Tom, login: qwerty, password: 123456
同様の方法で、モデルとそのプロパティの両方によるフィルタリングが可能です。
# ユーザーを獲得する
tom = User.objects.get(name="Tom")
# ユーザーアカウントを取得する
tom_acc = Account.objects.get(user=tom)
print(f"login: {tom_acc.login}, password: {tom_acc.password}")
# login: qwerty, password: 123456
# ユーザ名でアカウントを取得する
smith_acc = Account.objects.get(user__name="Smith")
print(f"login: {smith_acc.login}, password: {smith_acc.password}")
# ログイン名でユーザーを取得する
user = User.objects.get(account__login="qwerty")
print(user.name)
# Tom
関連記事