target model
관계 필드를 가지지 않은 모델
source model
관계 필드를 가진 모델
M:N model
의사 - 환자 모델을 생각했을 때 1:N 외래키를 이용했을 때는 한 의사에게 여러환자, 한 환자에게 여러의사가 있음을 동시에 표현하기가 어렵다.
class Doctor(models.Model):
name = models.TextField()
class Patient(models.Model):
name = models.TextField()
class Reservation(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
외래키를 삭제하고 별도의 예약모델을 새로 만든다. (중개 모델)
예약 모델은 의사와 환자에 각각 N:1 관계를 가진다. 예약모델의 의사, 환자 모두 FK이다.
예약이 생기면 예약모델을 이용하는 것이다.
의사, 환자가 예약모델을 참조하는 것은 target model이 source model을 참조하는 것이므로 역참조이다.
의사 doctor1에 예약된 환자를 확인하기 위해서는 역참조를 이용한다.
doctor1.reservation_set.all()으로 확인하면 된다.
환자 patient1이 예약한 의사를 확인하기 위해서는 patient1.reservation_set.all() 역참조를 이용한다.
ManyToManyField
Django의 ManyToManyField는 중개테이블을 자동으로 생성한다.
테이블 이름은 ManyToManyField 이름과 이를 포함하는 모델의 테이블이름을 조합하여 생성된다.
db_table 를 사용해서 중개 테이블의 이름을 변경할 수도 있다.
이 M:N 모델은 django의 ManyToManyField를 이용할 수 있다.
class Doctor(models.Model):
name = models.TextField()
class Patient(models.Model):
doctors = models.ManyToManyField(Doctor)
name = models.TextField()
manytomanyfield로 doctors라는 필드를 만들었다.
이렇게 모델을 정의하면,
name을 가진 doctor테이블, name을 가진 patient 테이블, patiend_id, doctor_id를 외래키로 가진 중개테이블이 생성된다.
위에서 만들었던 reservation 중개테이블이 자동으로 생성되는 것이다.
mtom field는 의사, 환자 어느쪽에 작성해도 관계없다.
하지만 참조, 역참조의 관계는 바뀌니 주의해야한다. 현재는 patiend가 doctor을 참조하는 것이고 반대는 역참조이다.
reservation 테이블을 생성했을 때와 달리 현재 상태에서는 환자, 의사가 예약을 만드는 것이다.
의사와 환자를 생성했다.
환자가 의사를 예약하는 방법이다.
현재 환자의 모델에는 의사를 doctors라는 필드에서 참조하고 있다.
환자의 doctors에 요소를 add 명령어를 이용하여 추가한다.
의사가 환자를 추가하는 방법이다.
의사 모델 클래스에는 환자에 대한 어떤 정보도 없기에 doctor1.patient.로는 사용할 수 없다.
역참조를 이용해서 add 해준다.
all()으로 전체를 조회할 수 있다.
중개테이블을 확인하면 위에서 추가한 예약 현황을 볼 수 있다.
doctor1.patient_set.remove(patient1)
patent2.doctors.remove(doctor1)
remove를 이용해서 예약을 없앨 수 있다.
class Patient(models.Model):
doctors = models.ManyToManyField(Doctor, related_name='patients')
name = models.TextField()
related_name을 설정하면 역참조시 사용할 manager name을 정해주는 것이다.
FK의 related_name과 동일하다.
doctor1.patient_set.all() ---> 오류발생!
doctor1.patients.all()
이제는 역참조시 자동으로 생성되는 _set 대신에 지정한 이름을 이용해야 한다.
중개 테이블이 외래키 2개 외에 필요한 것이 있을 때 중개모델 을 직접 작성하고 싶을 것이다.
중개테이블을 수동으로 지정하려는 경우 through 옵션을 사용하여 중개테이블을 나타내는 django 모델을 지정할 수 있다. 가장 일반적인 용도는 중개테이블에 추가 데이터를 사용할 때이다.
class Patient(models.Model):
doctors = models.ManyToManyField(Doctor, related_name='patients', through='Reservation')
name = models.TextField()
class Reservation(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
symptom = models.TextField()
reserved_at = models.DateTimeField(auto_now_add=True)
through 옵션을 추가했다.
증상, 예약일 추가데이터를 만들었다.
Reservation 모델을 직접 만들고, through에 만든 모델을 입력해준다.
이를 사용해도 아까와 같은 방식으로 한쪽에서 add, remove로 예약을 만들고 지울 수 있다.
doctor1 = Doctor.objects.create(name='alice')
patient1=Patient.objects.create(name='carol')
patient2 = Paitent.objects.create(name = 'dane')
의사, 환자 인스턴스 생성했다.
reservation1 = Reservation(doctor=doctor1, patient = patient1, symptom = 'headache')
중개테이블을 직접만들었을 때 처럼 예약테이블에서 직접 데이터를 추가할 수 있다.
patient2.doctors.add(doctor1, through_defaults={'symptom':'flu'})
환자에서 의사와의 관계를 추가했다.
throgh_defaults을 이용해서 딕셔너리 형태로 추가 데이터를 입력해준다.
doctor1.patients.remove(patient1)
동일하게 remove 작업 가능하다.
patient_set이 아닌 patients이다.
M:N 관계로 맺어진 두 테이블에는 변화가 없다.
Django의 ManyToManyField은 중개 테이블을 자동으로 생성한다.
ManyToManyField는 M:N 관계를 맺는 두 모델 어디에 위치해도 관계없지만, 참조와 역참조 방향은 주의해야 한다.
ManyToManyField(to, **options)
다대다 관계 설정시 사용하는 모델 필드
하나의 필수위치인자가 필요하다.
모델 필드의 relatedManager을 사용하여 관련 개체를 추가, 제거, 만들수있다.
add(), remove(), create(), clear()...
ManyToManyField - Arguments
1. related_name
target model이 source model을 참조할 때 사용할 manager name
FK의 related_name과 동일하다.
2. through
중개 테이블을 직접 작성하는 경우 through 옵션을 사용하여 중개테이블을 나타내는 django 모델을 지정한다.
일반적으로 중개테이블에 추가 데이터를 사용하는 다대다 관계와 연결하려는 경우에 사용된다.
3. symmetrical
기본값 : True
ManyToManyField가 동일한 모델을 가리키는 정의에서만 사용한다. (self)
User모델끼리의 following, follower 개념을 생각하면 된다.
True인 경우 (대칭) _set 매니저를 추가하지 않는다. source 모델의 인스턴스가 target 모델의 인스턴스를 참조하면 자동으로 target모델 인스턴스도 source모델 인스턴스를 참조하도록 하는 것이다.
(즉 내가 당신의 친구라면 당신도 나의 친구! )
대칭을 원하지 않는 경우 False로 설정하고, 내가 원하는 팔로잉, 팔로워 개념을 따로 관리할 수 있다.
related manager
N:1 혹은 N:M 관계에서 사용 가능한 문맥으로
역참조시 사용할 수 있는 manager를 생성한다.
N:1에서는 target 모델 객체만 사용가능하고, M:N 관계에서는 관련된 두 객체에서 모두 사용가능하다.
메서드 종류 : add(), remove(), create(), clear(), set() 등
add()
지정된 객체를 관련 객체 집합에 추가
이미 존재하는 관계에 사용하면 관계가 복제되지 않음
remove()
관련 객체 집합에서 지정된 모델 개체를 제거
내부적으로 QuerySet.delete()를 사용하여 관계가 삭제된다.
중개테이블 필드 생성 규칙
1. source model, target model이 다른경우
id
<containing_model>_id
<other_model>_id
2. 동일한 모델을 가리키는 경우 (self)
id
from_<model>_id
to_<model>_id
'Back-end > Django' 카테고리의 다른 글
Django M:N 관계 - 좋아요 버튼 / 프로필 페이지 (0) | 2022.10.12 |
---|---|
Aggregation (Grouping data) (0) | 2022.10.12 |
Django : static files 관리 / image 업로드, 출력, 수정, resizing (0) | 2022.10.11 |
django CRUD 기본 (0) | 2022.10.07 |
Django User 모델 참조 : settings.AUTH_USER_MODEL / get_user_model() (0) | 2022.10.05 |