장고에서는 Foreign Key (외래 키) 관계를 설정하는 방법으로 크게 세 가지가 있습니다.
1. 일대다 (One-to-Many) 관계
일대다 관계에서는 한 모델이 다른 모델의 여러 인스턴스와 연결될 수 있지만, 두 번째 모델(Book)의 인스턴스는 첫 번째 모델(Author)의 한 인스턴스에만 연결됩니다.
일대다 관계를 설정하기 위해 ForeignKey
필드를 사용할 수 있습니다.
예시:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
publication_date = models.DateField()
위의 예시에서 Book
모델은 Author
모델과 일대다 관계를 갖습니다. 하나의 작가는 여러 개의 책을 작성할 수 있지만, 각각의 책은 하나의 작가에만 속할 수 있습니다.
# views.py
from django.shortcuts import render
from .models import Author
def author_detail(request, author_id):
author = Author.objects.get(pk=author_id)
books = author.book_set.all()
return render(request, 'author_detail.html', {'author': author, 'books': books})
<!-- author_detail.html -->
<h1>{{ author.name }}</h1>
<h2>작품 목록</h2>
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% empty %}
<li>작품이 없습니다.</li>
{% endfor %}
</ul>
위의 예시에서 Author
모델과 Book
모델은 일대다 관계를 갖습니다. author_detail
뷰에서는 특정 작가의 작품 목록을 가져와서 템플릿에 전달합니다. 템플릿에서는 해당 작가의 작품들을 출력합니다.
2. 일대일 (One-to-One) 관계
일대일 관계에서는 한 모델의 인스턴스가 정확히 다른 모델의 한 인스턴스와 연결됩니다.
일대일 관계를 설정하기 위해 OneToOneField
필드를 사용할 수 있습니다.
예시:
# models.py
class Person(models.Model):
name = models.CharField(max_length=100)
class Passport(models.Model):
person = models.OneToOneField(Person, on_delete=models.CASCADE)
passport_number = models.CharField(max_length=20)
expiration_date = models.DateField()
위의 예시에서 Passport
모델은 Person
모델과 일대일 관계를 갖습니다. 각 사람은 하나의 여권을 가지며, 각 여권은 하나의 사람에게 속합니다.
# views.py
from django.shortcuts import render
from .models import Person
def person_detail(request, person_id):
person = Person.objects.get(pk=person_id)
passport = person.passport
return render(request, 'person_detail.html', {'person': person, 'passport': passport})
<!-- person_detail.html -->
<h1>{{ person.name }}</h1>
<h2>여권 정보</h2>
<p>여권 번호: {{ passport.passport_number }}</p>
<p>만료일: {{ passport.expiration_date }}</p>
위의 예시에서 Person
모델과 Passport
모델은 일대일 관계를 갖습니다. person_detail
뷰에서는 특정 사람의 여권 정보를 가져와서 템플릿에 전달합니다. 템플릿에서는 해당 사람의 여권 정보를 출력합니다.
3. 다대다 (Many-to-Many) 관계:
다대다 관계에서는 한 모델의 여러 인스턴스가 다른 모델의 여러 인스턴스와 연결될 수 있으며, 그 반대도 가능합니다.
다대다 관계를 설정하기 위해 ManyToManyField
필드를 사용할 수 있습니다.
예시:
# models.py
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
name = models.CharField(max_length=100)
students = models.ManyToManyField(Student)
위의 예시에서 Course
모델은 Student
모델과 다대다 관계를 갖습니다. 각 과목은 여러 학생들이 수강할 수 있고, 각 학생도 여러 과목을 수강할 수 있습니다.
# views.py
from django.shortcuts import render
from .models import Course
def course_detail(request, course_id):
course = Course.objects.get(pk=course_id)
students = course.students.all()
return render(request, 'course_detail.html', {'course': course, 'students': students})
<!-- course_detail.html -->
<h1>{{ course.name }}</h1>
<h2>수강생 목록</h2>
<ul>
{% for student in students %}
<li>{{ student.name }}</li>
{% empty %}
<li>수강생이 없습니다.</li>
{% endfor %}
</ul>
위의 예시에서 Course
모델과 Student
모델은 다대다 관계를 갖습니다.
역참조 관계에서도 동일한 원리로 사용할 수 있습니다. 역참조 관계에서는 _set
접미사를 사용하여 역참조 매니저를 사용할 수 있습니다. 예를 들어, 위의 예시에서 Author
모델에는 book_set
이라는 역참조 매니저가 자동으로 생성됩니다. 이를 통해 해당 작가와 관련된 모든 책을 가져올 수 있습니다. 마찬가지로 일대일 관계와 다대다 관계에서도 역참조 매니저를 사용할 수 있습니다.
역참조
일대다 (One-to-Many) 관계에서의 역참조:
# views.py from django.shortcuts import render from .models import Book def book_detail(request, book_id): book = Book.objects.get(pk=book_id) author = book.author return render(request, 'book_detail.html', {'book': book, 'author': author})
<!-- book_detail.html --> <h1>{{ book.title }}</h1> <h2>작가 정보</h2> <p>작가 이름: {{ author.name }}</p> <p>작가 이메일: {{ author.email }}</p>
위의 예시에서
Book
모델은Author
모델과 일대다 관계를 갖습니다.book_detail
뷰에서는 특정 책의 작가 정보를 가져와서 템플릿에 전달합니다. 템플릿에서는 해당 책의 작가 정보를 출력합니다.일대일 (One-to-One) 관계에서의 역참조:
# views.py from django.shortcuts import render from .models import Passport def passport_detail(request, passport_id): passport = Passport.objects.get(pk=passport_id) person = passport.person return render(request, 'passport_detail.html', {'passport': passport, 'person': person})
<!-- passport_detail.html --> <h1>여권 정보</h1> <p>여권 번호: {{ passport.passport_number }}</p> <p>만료일: {{ passport.expiration_date }}</p> <h2>소유자 정보</h2> <p>이름: {{ person.name }}</p> <p>나이: {{ person.age }}</p>
위의 예시에서
Passport
모델은Person
모델과 일대일 관계를 갖습니다.passport_detail
뷰에서는 특정 여권의 소유자 정보를 가져와서 템플릿에 전달합니다. 템플릿에서는 해당 여권의 소유자 정보를 출력합니다.다대다 (Many-to-Many) 관계에서의 역참조:
# views.py from django.shortcuts import render from .models import Student def student_detail(request, student_id): student = Student.objects.get(pk=student_id) courses = student.course_set.all() return render(request, 'student_detail.html', {'student': student, 'courses': courses})
<!-- student_detail.html --> <h1>{{ student.name }}</h1> <h2>수강한 과목 목록</h2> <ul> {% for course in courses %} <li>{{ course.name }}</li> {% empty %} <li>수강한 과목이 없습니다.</li> {% endfor %} </ul>
위의 예시에서
Student
모델과Course
모델은 다대다 관계를 갖습니다.student_detail
뷰에서는 특정 학생이 수강한 과목 목록을 가져와서 템플릿에 전달합니다. 템플릿에서는 해당 학생이 수강한 과목들을 출력합니다.
위의 예시 코드에서는 역참조 매니저인 _set
을 사용하여 역참조를 수행하고 있습니다. 역참조 매니저를 사용하면 해당 모델과 관련된 역방향 관계에 있는 객체들을 가져올 수 있습니다.
related_name
related_name은 역참조 시 사용되는 이름을 지정하는 기능입니다. 다음은 related_name을 사용하는 예시입니다.
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
위의 예시에서 Book
모델의 author
필드는 Author
모델과의 외래키 관계를 나타냅니다. related_name='books'
는 Author
모델에서 Book
모델과의 역참조 시 사용할 이름을 지정하는 부분입니다.
이제 역참조를 사용하여 Author
모델과 관련된 책들을 가져오는 예시를 보겠습니다.
author = Author.objects.get(id=1)
books = author.books.all()
위의 코드에서 author.books.all()
은 Author
모델의 역참조 매니저 books
를 통해 해당 작가와 관련된 모든 책들을 가져옵니다.
related_name
을 설정함으로써 역참조 시 사용할 이름을 명시적으로 지정할 수 있으며, 이를 통해 보다 직관적이고 명확한 코드를 작성할 수 있습니다.
'Python > Django' 카테고리의 다른 글
Django ORM에서 던더(__) (0) | 2023.07.07 |
---|---|
Type hint 적용후 circular dependency 문제 해결법 (0) | 2023.06.30 |
(Django) reverse와 reverse_lazy 차이 (0) | 2023.06.23 |
Django로 비밀번호 유효성 검사 구현하기 (0) | 2023.06.17 |
UniqueConstraint 사용 예시 (0) | 2023.04.05 |