# hospitals/models.py
from django.db import models
# Create your models here.
class Doctor(models.Model):
name = models.TextField()
def __str__(self):
return f'{self.name} 전문의'
class Patient(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
name = models.TextField()
def __str__(self):
return f'{self.pk}번 환자 {self.name}'
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py shell_plus
In [1]: doctor1 = Doctor.objects.create(name='alice')
In [2]: patient1 = Patient.objects.create(name='carol', doctor=doctor1)
In [3]: doctor2 = Doctor.objects.create(name='bella')
In [4]: patient2 = Patient.objects.create(name='dane', doctor=doctor2)
In [6]: patient4 = Patient.objects.create(name='carol', doctor=doctor1, doctor2)
Cell In[6], line 1
patient4 = Patient.objects.create(name='carol', doctor=doctor1, doctor2)
^
SyntaxError: positional argument follows keyword argument
# hospitals/models.py
class Patient(models.Model):
# 외래 키 삭제
# doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
name = models.TextField()
def __str__(self):
return f'{self.pk}번 환자 {self.name}'
class Reservation(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
def __str__(self):
return f'{self.doctor_id}번 의사의 {self.patient_id}번 환자'
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py shell_plus
In [2]: doctor1 = Doctor.objects.create(name='alice')
In [3]: patient1 = Patient.objects.create(name='carol')
In [5]: Reservation.objects.create(doctor=doctor1, patient=patient1)
Out[5]: <Reservation: 1번 의사의 1번 환자>
# 의사 -> 예약 정보 찾기
In [6]: doctor1.reservation_set.all()
Out[6]: <QuerySet [<Reservation: 1번 의사의 1번 환자>]>
# 환자 -> 예약 정보 찾기
In [7]: patient1.reservation_set.all()
Out[7]: <QuerySet [<Reservation: 1번 의사의 1번 환자>]>
In [8]: patient2 = Patient.objects.create(name='dane')
In [10]: Reservation.objects.create(doctor=doctor1, patient=patient2)
Out[10]: <Reservation: 1번 의사의 2번 환자>
# 의사 -> 환자 목록
In [11]: doctor1.reservation_set.all()
Out[11]: <QuerySet [<Reservation: 1번 의사의 1번 환자>, <Reservation: 1번 의사의 2번 환자>]>
Django는 ManyToManyField를 통해 중개 테이블을 자동으로 생성한다.
class Patient(models.Model):
# 외래 키 삭제
# doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
# ManyToManyField 작성
doctors = models.ManyToManyField(Doctor)
name = models.TextField()
def __str__(self):
return f'{self.pk}번 환자 {self.name}'
# Reservation Class 주석 처리
# class Reservation(models.Model):
# doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
# patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
# def __str__(self):
# return f'{self.doctor_id}번 의사의 {self.patient_id}번 환자'
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py shell_plus
In [2]: doctor1 = Doctor.objects.create(name='alice')
In [3]: patient1 = Patient.objects.create(name='carol')
In [4]: patient2 = Patient.objects.create(name='dane')
# patient1의 doctor1에게 예약
In [5]: patient1.doctors.add(doctor1)
# patient1 : 자신이 예약한 의사 목록 확인
In [6]: patient1.doctors.all()
Out[6]: <QuerySet [<Doctor: alice 전문의>]>
# doctor1 : 자신의 예약된 환자 목록 확인
In [7]: doctor1.patient_set.all()
Out[7]: <QuerySet [<Patient: 1번 환자 carol>]>
# doctor1이 patient2을 예약
In [8]: doctor1.patient_set.add(patient2)
# doctor1 : 자신의 예약 환자목록 확인
In [9]: doctor1.patient_set.all()
Out[9]: <QuerySet [<Patient: 1번 환자 carol>, <Patient: 2번 환자 dane>]>
# patient1, 2 : 자신이 예약한 의사 목록 확인
In [11]: patient1.doctors.all()
Out[11]: <QuerySet [<Doctor: alice 전문의>]>
In [12]: patient2.doctors.all()
Out[12]: <QuerySet [<Doctor: alice 전문의>]>
.remove()
사용# doctor1이 patient1 진료 예약 취소
In [13]: doctor1.patient_set.remove(patient1)
In [16]: doctor1.patient_set.all()
Out[16]: <QuerySet [<Patient: 2번 환자 dane>]>
In [17]: patient1.doctors.all()
Out[17]: <QuerySet []>
# patient2가 doctor1 진료 예약 취소
In [18]: patient2.doctors.remove(doctor1)
In [19]: patient2.doctors.all()
Out[19]: <QuerySet []>
In [20]: doctor1.patient_set.all()
Out[20]: <QuerySet []>
related_name
argumentclass Patient(models.Model):
# ManyToManyField - related_name 작성
doctors = models.ManyToManyField(Doctor, related_name='patients')
name = models.TextField()
def __str__(self):
return f'{self.pk}번 환자 {self.name}'
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py shell_plus
# 1번 의사 조회하기
In [1]: doctor1 = Doctor.objects.get(pk=1)
# 에러 발생(related_name 을 설정하면 기존 _set manager는 사용할 수 없음)
In [2]: doctor1.patient_set.all()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[2], line 1
----> 1 doctor1.patient_set.all()
AttributeError: 'Doctor' object has no attribute 'patient_set'
# 변경 후
In [3]: doctor1.patients.all()
Out[3]: <QuerySet []>
through
argumentclass Patient(models.Model):
doctors = models.ManyToManyField(Doctor, through='Reservation')
name = models.TextField()
def __str__(self):
return f'{self.pk}번 환자 {self.name}'
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)
def __str__(self):
return f'{self.doctor_id}번 의사의 {self.patient_id}번 환자'
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py shell_plus
In [1]: doctor1 = Doctor.objects.create(name='alice')
In [2]: patient1 = Patient.objects.create(name='carol')
In [3]: patient2 = Patient.objects.create(name='dane')
In [4]: reservation1 = Reservation(doctor=doctor1, patient=patient1, symptom='headache')
In [5]: reservation1.save()
In [6]: doctor1.patient_set.all()
Out[6]: <QuerySet [<Patient: 1번 환자 carol>]>
In [7]: patient1.doctors.all()
Out[7]: <QuerySet [<Doctor: alice 전문의>]>
In [8]: patient2.doctors.add(doctor1, through_defaults={'symptom':'flu'})
In [9]: doctor1.patient_set.all()
Out[9]: <QuerySet [<Patient: 1번 환자 carol>, <Patient: 2번 환자 dane>]>
In [10]: patient2.doctors.all()
Out[10]: <QuerySet [<Doctor: alice 전문의>]>
In [11]: doctor1.patient_set.remove(patient1)
In [12]: patient2.doctors.remove(doctor1)
ManyToManyField(to, **options)
add()
, remove()
, create()
, clear()
db_table
arguments을 사용하여 중개 테이블의 이름을 변경할 수도 있음# 예시
class Person(models.Model):
friends = models.ManyToManyField('self')
friends = models.ManyToManyField('self', symmetrical=False)
add()
, remove()
, create(), clear(), set() 등QuerySet.delete()
를 사용하여 관계 삭제