31
29

More than 3 years have passed since last update.

【Django】1対多の関係( related_name, _set.all() )について

Last updated at Posted at 2020-06-23

はじめに

 Djangoにてモデル同士を紐づける際に用いるmodels.ForeignKey()の引数の中でrelated_nameというパラメータがあるが、いつ使われるのかが分からなかったので調べてみた。

前提

 今回は以下のように、CategoryモデルとPostモデルを作成して考える。

apps/models.py
class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.name

class Post(models.Model):
    category = models.ForeignKey(to=Category, on_delete=models.CASCADE)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()

    def __str__(self):
        return self.title

 上のコードでcategoryオブジェクトを3つ、Postオブジェクトを6つ生成し、次の図の様な関係をもつとする。
スクリーンショット 2020-06-23 14.55.56.png

 以下2つの場合分けを行いそれぞれの方法を考える。

  • 二次関数(post.id=1)に紐づくcategoryを取得したい時《多→1の参照》
  • 社会(category.id=3)に紐づくpostをすべて取得したい時《1→多の参照》

多 → 1 への参照方法

 オブジェクト.フィールド名で取得可能

>>> post1 = Post.object.get(id=1)
>>> post1
<Post: 二次関数>
>>> post1.category
<Category: 数学>

1 → 多 への参照方法 【 _set.all() 】

 オブジェクト.モデル名(小文字)_set.all()で取得可能

>>> category3 = Category.object.get(id=3)
>>> category3
<Category: 社会>
>>> category3.post_set.all()
<QuerySet [<Post: 坂本龍馬>, <Post: 鎌倉幕府>]>

※ .all()の他に.filter()や.count()などを使って絞り込みやオブジェクト数をカウントしたりもできる。

related_nameとは

  • models.ForeignKeyの引数の一つで別になくても良い。
  • related_nameを指定するとモデル名(小文字)_setに置き換えて使用可能となる。
  • related_name=’posts’とすると先ほどの例では、
    category3.post_set.all() →→ category3.posts.all()
    となり、より直感的に分かるようになる。

引数としてrelated_nameを追加

apps/models.py
class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

class Post(models.Model):
    category = models.ForeignKey(to=Category, on_delete=models.CASCADE, related_name='posts') #追加
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()

related_nameを活用する

>>> category3 = Category.object.get(id=3)
>>> category3
<Category: 社会>
>>> category3.posts.all() #変更
<QuerySet [<Post: 坂本龍馬>, <Post: 鎌倉幕府>]> # ←結果は同じ
31
29
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
31
29