【Python】Djangoで複数のモデル間でリレーションの取得する

【Python】Djangoで複数のモデル間でリレーションの取得する

こんにちは、nishi_talk(@nishi_talk)です。
Django(ジャンゴ)で複数のモデル間でリレーションの取得の方法をご紹介します。




まずはモデル

項目はざっくりイメージ。

class Company(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Post(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    company = models.ForeignKey(Company, verbose_name='投稿', on_delete=models.CASCADE)

class Post_detail(models.Model):
    body = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    post = models.ForeignKey(Post, verbose_name='投稿詳細', on_delete=models.CASCADE)

リレーションはこんな感じで設定しました。

(1)Company <-> (多)Post(1) <-> (多)Post_detail

データベースはこんな感じ

mysql> show columns from company;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | NO   |     | NULL    |                |
| created_at | datetime(6)  | NO   |     | NULL    |                |
| updated_at | datetime(6)  | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

mysql> show columns from post;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| created_at | datetime(6)  | NO   |     | NULL    |                |
| updated_at | datetime(6)  | NO   |     | NULL    |                |
| company_id | int(11)      | NO   | MUL | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

mysql> show columns from post_detail;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| id         | int(11)     | NO   | PRI | NULL    | auto_increment |
| created_at | datetime(6) | NO   |     | NULL    |                |
| updated_at | datetime(6) | NO   |     | NULL    |                |
| post_id    | int(11)     | NO   | MUL | NULL    |                |
+------------+-------------+------+-----+---------+----------------+

CompanyのPostを取得

# view.pyに記述
from .models import Company, Post, Post_detail
post = Post.objects.filter(company_id__exact=1).all()

Postのオブジェクトからcompany_idが1のオブジェクトを取得します。
company_idの後にField lookupsを指定する。exactは一致するって意味みたい。
Field lookupsの説明はドキュメントを参考に。

QuerySet API reference



Companyからpost_detailを取得する

# view.pyに記述
from .models import Company, Post, Post_detail
post_detail = Post_detail.objects.filter(post__company__id=1).all()

Post_detailのオブジェクトからcompany_idが1のオブジェクトを取得します。
filter()内は 「table_name」__「table_name」__「column_name」で複数テーブルをまたがってJoin。
上記の例だと「Post → Company → Company内のID」って感じでjoinしてる。

参考記事

SQLのSELECT文を、DjangoのQuerySet APIで書いてみた