14
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Django/Related objects(add, create, remove, clear, set)まとめ

Last updated at Posted at 2020-01-25

書くこと

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のGitHubリンク(OneToMany)

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について改めてじっくりドキュメントを読んでみました。
特に引数で渡すオプションについての理解は曖昧だったので、同じような誰かの役に立つことを願っています。

参照

14
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?