카테고리 없음

스파르타 AI-8기 TIL(12/19)-Django

kimjunki-8 2024. 12. 19. 21:06

자, 알아야 할 것이 있습니다

먼저

forms와 models의 관계

어제 설명이 잘못되었음을 튜터님을 통해 느꼈다.
먼저, 저 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만 등록


관계 조회
수업에서 학생 목록 조회:

math_students = course1.students.all()
print(math_students)  # <QuerySet [<Student: Alice>, <Student: Bob>]>



학생이 등록한 수업 조회:

alice_courses = student1.course_set.all()
print(alice_courses)  # <QuerySet [<Course: Math>, <Course: Science>]>


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

대충 이렇게?

그런데 만약 자기 자신과 맺어야 한다면?(팔로우 기능)

 

그럼 과제하러 이만...