書くこと
add, create, remove, clear, setってどう使うんだっけというのを何度か調べてしまっていました。
その度英語を読むのは面倒なので、日本語でまとめておきます。
Django Documentation / Related objects reference
用意する Model,データ
from django.db import models
class Reporter(models.Model):
pass
class Article(models.Model):
title = models.CharField(max_length=255, null=True)
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
r1 = Reporter.objects.create(name='reporter1')
r2 = Reporter.objects.create(name='reporter2')
a1 = Article.objects.create(title='article1', reporter=r1)
a2 = Article.objects.create(title='article2', reporter=r1)
a3 = Article.objects.create(title='article3', reporter=r2)
各メソッドについて
add(*objs, bulk=True, through_defaluts=None)
addメソッドを使うことで親子関係における子テーブルの外部キーを更新することが出来ます。
使用例
>>> r1.article_set.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>]>
>>> r2.article_set.all()
<QuerySet [<Article: Article object (3)>]>
>>> r2.article_set.add(a1,a2)
>>> r1.article_set.all()
<QuerySet []>
>>> r2.article_set.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>
bulk=False
bulk=False
を使うことでまだsaveされていないobjectを引数として渡すことができます。
ただし、bulk=False
となっている通り、addするobjectの数だけクエリが発行されます。
>>> r1.article_set.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>]>
>>> new_a1 = Article()
>>> new_a2 = Article()
>>> r1.article_set.add(new_a1, new_a2, bulk=False)
>>> r1.article_set.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (4)>, <Article: Article object (5)>]
INSERT INTO `article` (`reporter_id`) VALUES (1) # new_a1
INSERT INTO `article` (`reporter_id`) VALUES (1) # new_a2
create(through_defaluts=None, **kwargs)
createメソッドを使うことで、少ない記述量で新しくレコードを作成することが出来ます。
>>> r1.article_set.create()
>>> r1.article_set.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>
これは以下と同様の結果になります。
>>> new_a = Article(reporter=r1)
>>> new_a.save()
>>> r1.article_set.all()
remove(*objs, bulk=True)
remove()
はForeignKeyをNullに更新してくれます。
ForeignKey(null=True)
の場合のみ使うことが出来ます。
上で用意したModelでForeignKey(null=True)
としたとすると、以下のように使うことが出来ます。
>>> r1.article_set.remove(a1, a2)
bulk=False
add()と同様にbulk=False
を渡すことで、レコードを一件ずつ更新することも出来ます。
>>> r1.article_set.remove(a1, a2, bulk=False)
>>> r1.article_set.all()
<QuerySet []>
bulk=True
の場合、QuerySet.update()
が呼ばれますが、bulk=False
の場合、save()
が複数回呼ばれます。
clear(bulk=True)
clear()
は全ての子のForeignKeyをNullに更新してくれます。
clear()
同様にForeignKey(null=True)
の場合のみ使うことが出来ます。
>>> r1.article_set.clear()
>>> r1.article_set.all()
<QuerySet []>
bulk=False
>>> r1.article_set.clear(bulk=False)
>>> r1.article_set.all()
<QuerySet []>
これもremove()同様、save()
が複数回呼ばれます。
set(objs, bulk=True, clear=False, through_defaults=None)
set()
は中でadd()
, remove()
, clear()
が動いています。
bulk=True/False
を引数として渡すと、中で動いているこれらのメソッドの引数にbulk
が入ります。
clear=False
>>> r1.article_set.set([a1, a3], bulk=False)
は以下と同じです。
>>> r1.article_set.remove(a2, bulk=False)
>>> r1.article_set.add(a1, a3, bulk=False)
clear=True
>>> r1.article_set.set([a1, a3], clear=True)
は以下と同じです。
>>> r1.article_set.clear()
>>> r1.article_set.add(a1, a3)
まとめ
以上DjangoのRelated objectsについて改めてじっくりドキュメントを読んでみました。
特に引数で渡すオプションについての理解は曖昧だったので、同じような誰かの役に立つことを願っています。