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.useruser.article_setarticle.like_usersuser.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')