DBを参照したいデータに.objectsが必要なわけ
アプリケーション内で以下のようなモデルを作成しました.
class BaseMeta(models.Model):
create_at = models.DateTimeField(auto_now_add=True)#insert時に現在時刻を取得
update_at = models.DateTimeField(auto_now_add=True)#update時に現在時刻を取得
class Meta:
abstract = True#本クラスではDBにテーブルを作らない
class Person(BaseMeta):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
birthday = models.DateField(default=date(1990,1,1))
email = models.EmailField(db_index=True)#index:検索高速化
salary = models.FloatField(null=True)
memo = models.TextField()
web_site = models.URLField(null=True)
class Meta:#オーバーライド
db_table = 'person'#table名
indexes = [models.Index(fields=['first_name','last_name'])]#複合インデックス
ordering = ['salary']
def __str__(self)
return f"{self.pk}: {self.first_name}, {self.last_name}"
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()
from ModelApp.models import Person
#すべてのレコードを取得
persons = Person.objects.all()#←これ
for p in persons:
print(p.pk, p.first_name,p.last_name)
ここの.objectsとは何?
と思い調べました.
結果
Django の モデルマネージャー(Manager) の仕組みによるためである.
つまり,Personはmodels.Modelを継承しているため、Djangoが自動的にそのクラスにobjectsというManagerのクラス変数として追加します。(インスタンス変数だと各インスタンスごとに異なるobjectsをもつため)
Django の Manager クラスは、django.db.models.Manager に定義されています。
以下のように解釈できます.
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
# デフォルトの Manager (django.db.models.Manager) が自動で追加される
# objects = models.Manager() が内部で行われる
このように,クラス継承によってPersonクラスは「自分自身」.objectsを経由してManagerのもつメソッドを使えるようになるわけです.
これによってできること
1. models.Modelにはobjectsという名前でManagerが自動的に定義されており、それがPersonクラスに「継承」という形で追加されます。
このobjectsを通じて、Personクラスに対するデータベースクエリができるようになります。
2. 自作メソッドを作れる(QuerySetを渡してあげる)
Managerはこのように定義されていて,
class Manager(BaseManager.from_queryset(QuerySet)):
pass
QuerySetをたとえばこのように渡します.
from django.db import models
class PersonQuerySet(models.QuerySet):
def with_salary(self):
return self.filter(salary__isnull=False)
# PersonQuerySet を持つ Manager を作成
PersonManager = models.Manager.from_queryset(PersonQuerySet)
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
salary = models.FloatField(null=True, blank=True)
objects = PersonManager() # カスタム Manager を適用
persons = Person.objects.with_salary() # salary が NULL でないデータを取得
このように,自作でメソッド作成可能です.
まとめ
使いたいクラス(Person)にmodels.Modelを継承させることでPerson.objects.all()など簡単にデータ参照できる.
これは,Managerクラス(objects = models.Manager()が内部的に行われている)を継承し,データ操作用のobjects(=インターフェース?)を与えたため
解釈違いや発展があればご教示お願いたします