Djangoでの逆参照の使用


正の参照
:私が参照したテーブル・アクセス、オブジェクトに他のオブジェクトがあるForeignKey、または関係が1:1の場合に参照
逆参照
:参照先のテーブルへのアクセス
別のオブジェクトにForeignKeyまたはN:N関係がある場合は、そのオブジェクトを参照する他のオブジェクトを参照します.
簡単なMtoM関係を作成しました:書籍と著者のデータモデル.
(本には複数の作者がいるので、作者も複数の本を書くことができます)
models.py
from django.db import models

class Book(models.Model):
    title        = models.CharField(max_length=45)
    release_date = models.DateField()
    price        = models.IntegerField()
   
    class Meta:
        db_table = "books"

class Author(models.Model):
    name = models.CharField(max_length=45)
    age  = models.IntegerField()
    Univ = models.CharField(max_length=45)

    class Meta:
        db_table = "authors"

class Bookauthor(models.Model):
    book   = models.ForeignKey("Book", on_delete=models.CASCADE)
    author = models.ForeignKey('Author', on_delete=models.CASCADE)

    class Meta: 
        db_table = "books_authors"
モデルを移植した後、適切にデータベースに書籍と著者を格納します.(真ん中のテーブルにも作者と本を合わせて値を保存しています.)
データベース・テーブルを格納するフィールド

今はビューpyファイルに格納されているデータベースに格納されているすべての書籍を表示するクラスを作成し、その本を執筆している著者の情報もリストに表示する必要があります.
この場合は逆参照を用いることができるが,まず逆参照を用いずに正参照を用いて中間表を通過する方法を試みた.
views.py
from django.http import JsonResponse
from django.views import View

from books.models import *

class Bookview(View):
    def get(self, request):
        books  = Book.objects.all()
        authors = Bookauthor.objects.all()
        results = [{
            "1. 제목" : book.title,
            "2. 출간일": book.release_date,
            "3. 가격" : book.price,
            "4. 저자" : [{
                "이름" : author.author.name,
                "나이" : author.author.age,
                "학력" : author.author.Univ
            } for author in authors
                if author.book == book]
        } for book in books] 
    
        return JsonResponse({"책" : results}, status=200)
すべての中間表を導入した後,List Comphensionを用いて図書データベース中の本と中間表中の本の情報を比較し,2冊の本の情報が一致すると,中間表中の本の著者の情報をリストに入れて返信する.
しかし,このようにコードを記述するとかなり複雑になり,コードの可読性も低下する.
if文を使わない方法もあります.
class Bookview(View):
    def get(self, request):
        books  = Book.objects.all()
        results = [{
            "1. 제목" : book.title,
            "2. 출간일": book.release_date,
            "3. 가격" : book.price,
            "4. 저자" : [{
                "이름" : author.author.name,
                "나이" : author.author.age,
                "학력" : author.author.Univ
            } for author in Bookauthor.objects.filter(book = book)]
        } for book in books] 
    
        return JsonResponse({"책" : results}, status=200
Many to Manyフィールドの逆参照を使用してコードを記述してみます.
まずモデルにManytomayfieldを加えます.
models.py
from django.db import models

class Book(models.Model):
    title        = models.CharField(max_length=45)
    release_date = models.DateField()
    price        = models.IntegerField()
    to_author    = models.ManyToManyField("Author", through="Bookauthor", related_name="to_book")

    class Meta:
        db_table = "books"

class Author(models.Model):
    name = models.CharField(max_length=45)
    age  = models.IntegerField()
    Univ = models.CharField(max_length=45)

    class Meta:
        db_table = "authors"

class Bookauthor(models.Model):
    book   = models.ForeignKey("Book", on_delete=models.CASCADE)
    author = models.ForeignKey('Author', on_delete=models.CASCADE)

    class Meta: 
        db_table = "books_authors"
このツールを使用してViewクラスを作成します.
class Bookview(View):
    def get(self, request):
        books  = Book.objects.all()
        results = [{
            "1. 제목" : book.title,
            "2. 출간일": book.release_date,
            "3. 가격" : book.price,
            "4. 저자" : [{
                "이름" : author.name,
                "나이" : author.age,
                "학력" : author.Univ
            } for author in book.to_author.all()]
        } for book in books] 
    
        return JsonResponse({"책" : results}, status=200)
以前とは異なり、中間テーブルを個別に入力するのではなく、指定したMany to Manyフィールドを使用します.
そうすれば、私たちが欲しい本の作者を見つけやすくなります.また,ループ文のオブジェクト「book」にメソッドが続くため,コードを表示する人も理解しやすい.

Insomniaで確認したところ、本や本の中の情報がよく出ていました.
もちろん、Many to Manyを使用しなくても結果は同じですが、より効率的で可読性の高いコードです.