어제 설명이 잘못되었음을 튜터님을 통해 느꼈다. 먼저, 저 fields는 get_user_model()에 있는 fields들을 말하는 것이였다. 즉, 저것만 가져온다는 것이다. 그리고 저 UserChangForm을 상속 받는것은, 사실 중요한 의미가 있다. 우리가 model을 바꾸고 fields를 바꾸면, 딱 그 부분만 바뀐다는 소리입니다.
즉, 안에 함수, 뭐 여러가지 기능은 그대로 가져옴과 동시에, 딱 저 부분만 바꿔서 새로 만들어진 것을 쓴다는 소리입니다. 예를 들어, 기어 1,2,3이 있다고 했을 때, 딱 기어 1,2는 들고오지만, 3에서 뭐 기어의 숫자를 바꾼다던가 해서 3만 바꾼채로 기어 1,2,3을 쓰겠다는 소리입니다.
역참조?
먼저 foreignkey란? 두 모델 간에 "부모-자식" 관계를 만듭니다. "부모"는 참조되는 모델 (예: Author), "자식"은 참조하는 모델 (예: Book)입니다. 자식 모델에서 부모 모델의 특정 데이터를 가져다 쓸 수 있게 해줍니다.
Author 모델: 작가의 정보를 저장하는 모델입니다. 예: name과 email 필드가 있습니다.
Book 모델: 책 정보를 저장하는 모델입니다. author 필드는 ForeignKey를 사용해서 Author 모델과 연결합니다. on_delete=models.CASCADE: 작가(Author)가 삭제되면 그 작가가 쓴 책(Book)도 삭제됩니다.
여기서 중요한 점은 ForeignKey는 "1:N 관계"를 만듭니다. "한 명의 작가(Author)"가 "여러 권의 책(Book)"을 쓸 수 있습니다. 반대로, "한 권의 책(Book)"은 "한 명의 작가(Author)"만 가질 수 있습니다.
데이터 흐름 예시 1. "한 명의 작가가 쓴 모든 책 보기"
author = Author.objects.get(name="Jane Austen")
books = author.book_set.all() # 해당 작가가 쓴 모든 책을 가져옴
print(books)
# 출력: <QuerySet [<Book: Pride and Prejudice>, <Book: Emma>]>
book_set은 ForeignKey로 연결된 Book 객체들의 목록입니다. Author → 여러 Book 연결.
2. "한 권의 책의 작가 정보 보기"
book = Book.objects.get(title="Emma")
print(book.author) # 출력: Jane Austen
책(Book)은 하나의 작가(Author)만 참조할 수 있습니다. Book → 단일 Author 연결.
중요: 관계 방향은 ForeignKey 정의 위치에 따라 다름 ForeignKey는 정의된 모델이 "N측"입니다.
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE) # ForeignKey 정의
Book이 N: Book 모델은 여러 개의 객체를 만들 수 있고, 각 객체는 특정 Author와 연결됩니다. Author가 1: Author 모델은 한 번 정의되면, 여러 Book 객체에서 참조됩니다.
다시 설명하면: ForeignKey를 가진 모델 → "외부의 데이터를 참조(Foreign)하는 모델" → 이 모델이 관계에서 "N" 역할을 합니다. → Book 모델이 이에 해당합니다.
ForeignKey로 참조된 모델 → "참조되는 모델 (Parent)" → 이 모델이 관계에서 "1" 역할을 합니다. → Author 모델이 이에 해당합니다.
ManyToMany 관계
N:M 관계: 한 모델의 객체가 다른 모델의 여러 객체와 연결될 수 있고, 반대로도 가능합니다. 예를 들어, 학생(Student)과 수업(Course) 관계: 한 학생은 여러 수업을 들을 수 있고, 한 수업에는 여러 학생이 참여할 수 있습니다.
예시 1: ManyToManyField를 한쪽에 정의
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
title = models.CharField(max_length=200)
students = models.ManyToManyField(Student) # Course에서 Student와 연결
여기서 Course 모델에 students라는 ManyToManyField를 정의했지만, 반대로 Student 모델에 courses를 정의해도 동일한 결과를 얻습니다.
예제 2: 반대로 정의
class Student(models.Model):
name = models.CharField(max_length=100)
courses = models.ManyToManyField('Course') # Student에서 Course와 연결
class Course(models.Model):
title = models.CharField(max_length=200)
Student 모델에서 ManyToManyField를 정의해도 상관없습니다. Django는 자동으로 대칭적인 관계를 만들어줍니다.
데이터 생성
# 학생 생성
student1 = Student.objects.create(name="Alice")
student2 = Student.objects.create(name="Bob")
# 수업 생성
course1 = Course.objects.create(title="Math")
course2 = Course.objects.create(title="Science")
# 관계 추가
course1.students.add(student1, student2) # Math 수업에 Alice와 Bob 등록
course2.students.add(student1) # Science 수업에 Alice만 등록
ManyToManyField는 어느 모델에 정의하든 관계에는 차이가 없습니다. 하지만 가독성과 설계 논리를 고려해 결정하면 좋아요: 만약 "수업은 학생이 많다"는 관점이 중요하다면 Course에 정의. 반대로 "학생은 여러 수업을 듣는다"가 중요하면 Student에 정의.
중간 테이블
Django의 ManyToManyField는 두 모델 간의 N:M 관계를 저장하기 위해 중간 테이블(through table)을 자동으로 생성합니다. 이 중간 테이블이 데이터 저장소 역할을 하며, 관계를 효율적으로 관리합니다.
근데 솔직히 장고에서는 ManyToMany를 쓰면 자동으로 만들어주기 때문에 이 부분은 그냥 스킵하셔도 됩니다.
N:M 관계와 중간 테이블 ManyToManyField는 실제로 두 모델 간의 관계 데이터를 저장하기 위해 별도의 테이블을 만듭니다.
이 중간 테이블은 두 모델의 각 객체 ID를 저장합니다. Django는 이를 자동으로 생성하고 관리합니다.
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
title = models.CharField(max_length=200)
students = models.ManyToManyField(Student)
Django가 생성하는 중간 테이블 Django는 내부적으로 다음과 같은 중간 테이블을 만듭니다:
CREATE TABLE appname_course_students (
id SERIAL PRIMARY KEY,
course_id INT NOT NULL REFERENCES appname_course(id),
student_id INT NOT NULL REFERENCES appname_student(id)
);
이 테이블 이름은 <모델명>_<ManyToManyField명> 형태로 생성됩니다. 각 행은 Course와 Student 간의 관계를 저장합니다.
# 학생 생성
alice = Student.objects.create(name="Alice")
bob = Student.objects.create(name="Bob")
# 수업 생성
math = Course.objects.create(title="Math")
science = Course.objects.create(title="Science")
# 관계 추가
math.students.add(alice, bob) # Math 수업에 Alice와 Bob 등록
science.students.add(alice) # Science 수업에 Alice만 등록
중간 테이블에 저장된 데이터 (자동 생성)
| id | course_id | student_id |
|----|-----------|------------|
| 1 | 1 | 1 | # Math ↔ Alice
| 2 | 1 | 2 | # Math ↔ Bob
| 3 | 2 | 1 | # Science ↔ Alice