📗 Django 


ManyToMany Relationship

좋아요와 팔로우 기능은 어떻게 만드는 걸까?

 

  • 좋아요 기능이 뭘까?
    • User가 Article에 좋아요(Like)를 누르는 것
  • 저장해야 할 데이터는 뭘까?
    • User가 어떤 Article에 좋아요를 눌렀는지 저장

 

ManyToMany 🔗 공식 문서

  • 다대다(M:N) 관계 설정 시 사용하는 모델 필드이다.
    • 예시) 좋아요
      • 하나의 게시글도 여러 명의 유저에게 좋아요를 받을 수 있다
      • 한 명의 유저는 여러 개의 게시글을 좋아할 수 있다
  • 중계 테이블을 이용해서 관계를 표현
  • models.ManyToManyField(<classname>)을 이용해서 설정
  • M2M 관계가 설정되면 역참조시 사용가능한 _set이름의 RelatedManager를 생성합니다.
    • related_name으로 변경 가능
  • add(), remove()를 이용해서 관련 객체를 추가, 삭제할 수 있다.

 

좋아요 구현하기

  • articles/models
    • migration 실행
더보기
articles/models.py
    Like_users = models.ManyToManyField(
        settings.AUTH_USER_MODEL, related_name="Like_articles")

 

migration
python manage.py makemigrations
python manage.py migrate

 

 

새로 생긴 0003. article_like_users.py

 

 

중계 테이블도 만들어졌다


ORM 연습하기

▪️ article과 user 불러오기
더보기
# aritcle 가져오기
Article.objects.all()
# Users 불러오기
User.objects.all()
# article_1은 id 1로 지정하기
article_1 = Article.objects.get(id=1)

 

# admin_user는 id 1로 불러와지게 설정하기
admin_user = User.objects.get(id=1)
# MinKyung_user는 id 2로 불러와지게 설정하기
MinKyung_user = User.objects.get(id=2)
▪️ 좋아요 추가, 조회하기
더보기
article_1.Like_users.add(admin_user)
article_1.Like_users.add(MinKyung_user)
article_1.Like_users.all()
  • admin_user → article_1 : 좋아요
  • MinKyung_user → article_1 : 좋아요
  • article_1을 좋아하는 모든 user 목록
# 좋아요 취소하기
article_1.Like_users.remove(MinKyung_user)
# user가 article에 좋아요 남겼다고 작성할 수도 있다.
MinKyung.Like_articles.add(article_1)

 

왜 안 되나 했더니,

 

 

Like_users로 해둬서 안 됐던 거였다,,

like_users가 아니라 Like_users였던 것,,

▪️ article_article_like_users 중계테이블
더보기

 

  • article_1번 글에 user_id가 1과 2인 사람이 눌렀음을 보여줌
  • Django에서 자동으로 중계테이블을 만들어주었다.

좋아요에 ‘정도’를 표현하고 싶다면?

  • 중계테이블을 내가 직접 정의해줄 수도 있다

  • articles/urls
더보기
path('<int:pk>/like/', views.like, name="like"),
  • articles/views
더보기
# 좋아요
@require_POST
def like(request, pk):
    if request.user.is_authenticated:
        article = get_object_or_404(Article, pk=pk)
        # 만약 article에 좋아요가 user.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:articles")
    return redirect("accounts:login")
  • articles.html
더보기
 <form action="{% url "articles:like" article.pk %}" method="POST">
        {% csrf_token %}
        {% if request.user in article.Like_users.all %}
            <input type="submit" value="Cancle Like">
        {% else %}
            <input type="submit" value="Like">
        {% endif %}
    </form>

 

<article.pk에 like 주소로 가게끔>

 <form action="{% url "articles:like" article.pk %}" method="POST">
        {% csrf_token %}

 

<만약에, article.Like_users.all에 user가 있다면, 좋아요 취소>

 {% if request.user in article.Like_users.all %}
     <input type="submit" value="Cancle Like">

 

<article.Like_users.all에 user가 없다면, 좋아요>

{% else %}
    <input type="submit" value="Like">

 

 

 

되넹!


팔로우 

🤔 팔로우는 어떻게 구현할 수 있을까?
  • 한 명의 유저는 여러 명의 유저를 팔로우할 수 있어요!
  • 한 명의 유저는 여러 명의 팔로워를 가질 수 있어요!

⇒ M:N 관계

 

누구랑 m2m 관계를 맺어야 할까?

⇒ USER - USER

 

symmetrical

  • M2M Field가 동일한 모델(self)과 관계를 맺는 경우에 사용
  • symmetrical=True인 경우 한 방향에서 관계를 맺으면 반대 관계도 설정된다. (대칭)
    • 기본값은 True

팔로우 구현하기

  • accounts/models.py
    • migration 하기
더보기
class User(AbstractUser):
    followings = models.ManyToManyField(
        "self", related_name="followers", symmetrical=False)

 

migrate 하기
python manage.py makemigrations
python manage.py migrate

 

 

잘 생성됐다

  • users/urls.py
더보기
path("<int:user_id>/follow/", views.follow, name="follow"),
  • users/views.py
더보기
from django.shortcuts import render, redirect
from django.views.decorators.http import require_POST
from django.shortcuts import get_object_or_404
from django.contrib.auth import get_user_model

def users(request):
    return render(request, "users/users.html")

def profile(request, username):
    member = get_object_or_404(get_user_model(), username=username)
    context = {"member": member,}
    return render(request, "users/profile.html", context)

@require_POST
def follow(request, user_id):
    if request.user.is_authenticated:
        member = get_object_or_404(get_user_model(), pk=user_id)
        if member != request.user:
            if member.followers.filter(pk=request.user.pk).exists():
                member.followers.remove(request.user)
            else:
                member.followers.add(request.user)
        return redirect("users:profile", member.username)
    return redirect("accounts:login")
  • profile.html
더보기
{% extends 'base.html' %}

{% block content %}
    <h1>Profile of {{ member.username }}</h1>

    <div>
        <h2>username : {{ member.username }}</h2>

        {% if request.user != member %}
            <form action="{% url "users:follow" member.pk %}" method="POST">
                {% csrf_token %}
                {% if request.user in member.followers.all %}
                    <input type="submit" value="Unfollow">
                {% else %}
                    <input type="submit" value="Follow">
                {% endif %}
            </form>
        {% endif %}        
    </div>

    <a href="/index/">Back to the index</a>

{% endblock content %}

 

 

admin으로 들어가서 MinKyung 프로필에 들어가니까 작동 잘 된다.

 

🐾Recent posts