Programming Language/SQLite

SQLite_04)Foreign Key_2

Sergemeow 2023. 4. 12. 14:45

댓글과 유저를 Foregin Key로 연결하기

  • Comment 모델에 User 모델을 참조하는 외래키 작성
# articles/models.py

class Comment(models.Model):
	article = models.ForeignKey(Article, on_delete=models.CASCADE)
	user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
  • CommentForm 출력을 확인해보면 불필요한 필드인 user가 드롭다운으로 출력됨
  • user 필드에 작성해야하는 user 객체는 view 함수의 request 객체를 활용해야함
  • CommentForm의 출력필드 수정
class CommentForm(forms.ModelForm):
	...
	...
	exclude = ('article', 'user')
  • 댓글 작성 시 작성자 정보가 함께 저장될 수 있도록 save의 commit 옵션을 활용
def comments_create(request, pk):
	...
	...
	if comment_form.is_valid():
		...
		comment.user = request.user
		comment.save()
  • 작성자를 출력하기 위해서는 detail 템플릿에서 코드 추가
{{comment.user}}

{% if request.user == comment.user %} 
  • view의 comments_delete 함수에서 if 문 추가
def comments_delete(request, pk, comment_pk):
	...
	if request.user == comment.user:
		comment.delete()

인증된 사용자인 경우만 댓글 작성 및 삭제

  • comments_create
@require_POST
def comments_create(request, pk):
	if request.user.is_authenticated:
		article = Article.objects.get(pk=pk)
		comment_form = CommentForm(request.POST)
		if comment_form.is_valid():
			comment = comment_form.save(commit=False)
			comment.article = article
			comment.user = request.user
			comment.save()
		return redirect('articles:detail', article.pk)
	return redirect('accounts:login')
  • comments_delete
@require_POST
def comments_delete(request, article_pk, comment_pk):
	if request.user.is_authenticated:
		comment = Comment.objects.get(pk=comment_pk)
		if request.user == comment.user:
			comment.delete()
	return redirect('articles:detail', article_pk)
  • CommentForm 가리기
{% if request.user.is_authenticated %}
	<form action = "{% url ... %}" ...>
			...
	</form>
{% else %}
	...
{% endif %}

Many to many relationship

예시로, 의사와 환자간 예약 시스템을 구현

1) 중개 테이블 직접 구성

doctor, patient, reservation 테이블을 foreign key로 이음


2) ManyToManyField로 중개 테이블 자동 생성

class Patient(models.Model):
	doctors = models.ManyToManyField(Doctor)
	name = models.TextField()
	def __str__(self):
		return f'{self.pk}번 환자 {self.name}'
  • 테스트
doctor1 = Doctor.objects.create(name='alice')
patient1 = Patient.objects.create(name='carol')
patient2 = Patient.objects.create(name='dane')

# patient1이 doctor1에게 예약
patient1.doctors.add(doctor1)

# patient1이 예약한 의사 목록 확인
patient1.doctors.all()

# doctor1에게 예약된 환자 목록 확인
doctor1.patient_set.all()

# doctor1이 patient2를 예약
doctor1.patient_set.add(patient2)
# doctor1이 patient1 진료 예약 취소
doctor1.patient_set.remove(patient1)

# patient2가 doctor1 진료 예약 취소
patient2.doctors.remove(doctor1)
  • ‘related_name’ argument
    • target model이 source model을 참조할 때 사용할 manager name
    • ForeignKey()의 related_name과 동일
class Patient(models.Model):
	doctor = models.ManyToManyField(Doctor, related_name='patients')
# 기존에는 patient_set으로 접근 가능했음

3)ManyToManyField를 사용하고 중개모델은 직접 구성

  • through 설정 몇 Reservation Class 수정
  • 보통 추가데이터필드를 넣기 위해 사용
class Patient(models.Model):
	doctors = models.ManyToManyField(Doctor, through='Reservation')
	name = models.TextField()
	...

class Reservation(models.Model):
	doctor = models.ForeignKey(Doctor, on_delete=models.CAASCADE)
	patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
	symptom = models.TextField()
	reserved_at = models.DateTimeField(auto_now_add=True)
# 1. Reservation class를 통한 예약 생성
reservation1 = Reservation(doctor=doctor1, patient=patient1, symptom='headache')
reservation1.save()

# 2. Patient 객체를 통한 예약 생성
patient2.doctors.add(doctor1, through_defaults={'symptom':'flu'})

# 3. 예약 삭제
doctor1.patient_set.remove(patient1)
patient2.doctors.remove(doctor1)

'Programming Language > SQLite' 카테고리의 다른 글

SQLite_06)Fixtures  (0) 2023.04.12
SQLite_05)Foreign Key_3  (0) 2023.04.12
SQLite_03)Foreign Key_1  (0) 2023.04.12
SQLite_02)CRUD  (0) 2023.04.12
SQLite_01)Set up & Basics  (0) 2023.04.12