target model
source model
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}'
모델을 바꿔줘야 하는 상황 (Patient의 doctor FK 부분을 지우는)
데이터 베이스 초기화 후 Migration 진행 및 shell_plus 실행
모델 수정
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}'
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}번 환자'
variable_name = models.ManyToManyField(MTM 관계 맺을 Model명)
MTMF 사용하는걸로 모델 변경하면
또 이미 기존 모델의 형태로 데이터가 들어 있기 때문에 Migration이랑 DB 다 날리고 변경하자
(migrations 안의 __init__
은 지우지 말자)
Model 수정
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)
doctors = models.ManyToManyField(Doctor)
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}번 환자'
.remove()
만 사용하면 됨aaa.bbb_set.all()
이런식으로 했었음aaa.bbb.all()
하고 싶다면related_name
argument 사용하면 됨Django가 중계 테이블 만들어주는데 그럼 직접 중계모델을 작성해서 사용하는 경우는 Django를 사용할때 절대 없을까?
-> 직접 만들어야 하는 경우는 있음
Django가 만들어주는 중계 테이블엔 FK들어가는 column만 있음
근데, 아까 병원의 상황을 이어가자면 보통 증상, 예약일, 진료일 등 다른 데이터들을 중계 테이블에 넣어야 하는 상황이 분명히 존재함
-> 이때 직접 중계 테이블을 만들어야 함
근데 MTM이 만들어주는 중계 테이블에 field를 추가 및 삭제 하고 싶음
-> through
옵션 사용
through
를 통해 Reservation에 MTM 기능 사용할 수 있도록 모델 변경class Patient(models.Model):
# doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
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}번 환자'
ab_table
arguments을 사용하여 중개 테이블의 이름을 변경할 수도 있음 # articles/models.py
class Article(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
like_users = models.ManyToManyField(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=30)
content = models.TextField()
image = models.ImageField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.id}번째글 - {self.title}'
user.article_set.all()
-> 해당 유저가 작성한 모든 게시글 조회 class Article(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
like_users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='like_articles')
title = models.CharField(max_length=30)
content = models.TextField()
image = models.ImageField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.id}번째글 - {self.title}'
article.user
user.article_set
article.like_users
user.like_articles
# articles/urls.py
path('<int:article_pk>/like/', views.likes, name='likes'),
# articles/views.py
def likes(request, article_pk):
article = Article.objects.get(pk=article_pk)
# 좋아요 취소
if article.like_users.filter(pk=request.user.pk).exists():
article.like_users.remove(request.user)
# 좋아요
else:
article.like_users.add(request.user)
return redirect('articles:index')
.exist()
: QuerySet에 존재하는지 안하는지 확인 후 결과를 bool형으로 반환 <span>좋아요 : {{article.like_users.count}}개 </span>
<form action="{% url 'articles:likes' article.pk %}" method = "POST">
{% csrf_token %}
{% if request.user in article.like_users.all %}
<input type="submit" value="좋아요 취소">
{% else %}
<input type="submit" value="좋아요">
{% endif %}
</form>
3.
@require_POST
def likes(request, article_pk):
if request.user.is_authenticated:
article = Article.objects.get(pk=article_pk)
# 좋아요 취소
if article.like_users.filter(pk=request.user.pk).exists():
article.like_users.remove(request.user)
# 좋아요
else:
article.like_users.add(request.user)
return redirect('articles:index')
else:
return redirect('accounts:login')
# accounts/urls.py
path('profile/<int:pk>/',views.profile, name='profile'),
# accounts/views.py
@login_required
@require_GET
def profile(request, pk):
User = get_user_model()
person = User.objects.get(pk=pk)
context = {
'person' : person,
}
return render(request, 'accounts/profile.html', context)
{% extends 'base.html' %}
{% block content %}
<h1>{{person.username}} 님의 프로필</h1>
<div>
<div>
팔로잉 : {{person.followings.all|length}} / 팔로워 : {{person.followers.all|length}}
</div>
{% if request.user != person %}
<div>
<form action="{% url 'accounts:follow' person.pk %}" method = "POST">
{% csrf_token %}
{% if request.user in person.followers.all %}
<input type="submit" value="Unfollow">
{% else %}
<input type="submit" value="Follow">
{% endif %}
</form>
</div>
{% endif %}
</div>
<hr>
<h2>{{person.username}}'s 게시글</h2>
{% for movie in person.movie_set.all %}
<div>
<a href="{% url 'movies:detail' movie.pk %}">{{movie.title}}</a>
</div>
{% endfor %}
<h2>{{person.username}}'s 좋아요한 게시글</h2>
{% for movie in person.like_movies.all %}
<div>
<a href="{% url 'movies:detail' movie.pk %}">{{movie.title}}</a>
</div>
{% endfor %}
<hr>
<a href="{% url 'movies:index' %}">back</a>
{% endblock content %}
# base.html
<!--마이 페이지-->
<a href="{% url 'accounts:profile' user.pk %}">마이 페이지</a>
class User(AbstractUser):
followings = models.ManyToManyField('self', symmetrical=False, related_name='followers')
# accounts/urls.py
path('<int:user_pk>/follow/',views.follow, name='follow'),
# accounts/views.py
@require_POST
def follow(request, user_pk):
if request.user.is_authenticated:
User = get_user_model()
person = User.objects.get(pk=user_pk)
if person != request.user:
if person.followers.filter(pk=request.user.pk).exists():
person.followers.remove(request.user)
else:
person.followers.add(request.user)
return redirect('accounts:profile', person.pk)
else:
return redirect('accounts:login')