Django 에서 역참조 이용하기

Wonbin Lee·2022년 3월 20일
0

Django

목록 보기
3/6

정참조
: 내가 참조하는 table 접근, 해당 객체가 다른 객체의 ForeignKey를 가지고 있거나 1:1 관계인 상황에서 참조 하는 경우

역참조
:나를 참조하는 table 접근
다른 객체가 ForeignKey를 가지고 있거나 N:N 관계인 상황, 해당 객체를 참조하고 있는 다른 객체를 참조하려는 경우


간단한 MtoM(Many to Many) 관계인 책과 저자의 데이터 모델을 만들었다. (책도 여러명의 저자를 가질 수 있고, 저자도 여러가지책을 집필 할 수 있기 때문)

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"

모델들을 마이그레이션 해준 후 적당히, 데이터베이스에 책과 저자들을 저장해준다.(중간테이블에도 저자와 책을 맞춰서 값을 저장해준다.)


저장된 database table 들의 field



이제 views.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 Comprehension을 이용하여 books 데이터베이스에 있는 책과 중간테이블에 있는 책의 정보를 비교한후, 두 책의 정보가 일치하면 중간테이블의 책의 저자의 정보를 리스트에 넣어서 리턴해주는 것이다.
하지만 이렇게 코드를 짜게 되면 상당히 복잡하고, 코드의 가독성 또한 떨어져 보인다.

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 field를 이용한 역참조 방식으로 코드를 작성해보았다.
먼저 모델에 ManytoMany field를 넣어준다.

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를 이용하지 않아도 결과는 같게 나오지만, 훨씬 효율적이고 가독성이 좋은 코드가 된 것이다.

profile
Developer who level up every day ✌️

0개의 댓글