ManyToMany Relationship in Django
좋아요 (Like) 기능 구현
User가 특정 Article에 좋아요(Like)를 누르는 기능
→ User가 어떤 Article에 좋아요를 눌렀는지 저장
articles/models.py
1차 구현 (1:N 관계)
class Article(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
author = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="articles"
)
like_user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="like_articles",
null=True
)
- 동일 Article에 여러 명이 '좋아요' 누를 수 없음 → 해결 필요
2차 구현 (별도 중계 테이블 활용)
class ArticleLike(models.Model):
article = models.ForeignKey(
Article, on_delete=models.CASCADE, related_name="likes"
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="likes"
)
ArticleLike
테이블을 만들어 M:N 관계를 직접 처리 가능
ManyToManyField 활용한 최종 구현
class Article(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
author = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="articles"
)
like_users = models.ManyToManyField(
settings.AUTH_USER_MODEL, related_name="like_articles"
)
- Django의
ManyToManyField
를 활용, 중계 테이블을 자동 생성하여 간편하게 구현 가능 like_users.add(user)
및like_users.remove(user)
로 좋아요 추가/취소 가능
ManyToMany Field
Model field reference | Django documentation
The web framework for perfectionists with deadlines.
docs.djangoproject.com
좋아요 기능 관련 URL 및 뷰 구현
URL 설정 (articles/urls.py)
urlpatterns = [
path("<int:pk>/like/", views.like, name="like"),
]
View 함수 구현 (articles/views.py)
@require_POST
def like(request, pk):
if request.user.is_authenticated:
article = get_object_or_404(Article, pk=pk)
if article.like_users.filter(pk=request.user.pk).exists():
article.like_users.remove(request.user)
else:
article.like_users.add(request.user)
else:
return redirect("accounts:login")
return redirect("articles:articles")
좋아요 버튼 추가 (articles.html)
{% for article in articles %}
<form action="{% url 'articles:like' article.pk %}" method="POST">
{% csrf_token %}
{% if user in article.like_users.all %}
<input type="submit" value="좋아요 취소">
{% else %}
<input type="submit" value="좋아요">
{% endif %}
</form>
{% endfor %}
팔로우 (Follow) 기능 구현
한 명의 User가 여러 명의 User를 팔로우할 수 있음
한 명의 User는 여러 명의 팔로워를 가질 수 있음
→ User - User 간의 M:N 관계
모델 구현 (ManyToManyField 활용)
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
following = models.ManyToManyField(
"self", symmetrical=False, related_name="followers"
)
symmetrical=False
를 설정하여 대칭적이지 않은 관계(한쪽만 팔로우 가능) 구현- Django는 M2M 관계를 위한 자동 중계 테이블 생성
팔로우 기능 관련 URL 및 뷰 구현
URL 설정 (users/urls.py)
urlpatterns = [
path("<int:user_id>/follow/", views.follow, name="follow"),
]
View 함수 구현 (users/views.py)
@require_POST
def follow(request, user_pk):
if request.user.is_authenticated:
member = get_object_or_404(get_user_model(), pk=user_pk)
if request.user != member:
if request.user in member.followers.all():
member.followers.remove(request.user)
else:
member.followers.add(request.user)
return redirect("users:profile", member.username)
return redirect("accounts:login")
팔로우 버튼 추가 (profile.html)
{% block content %}
<h1>{{ member.username }}의 프로필 페이지</h1>
<div>
<h2>username: {{ member.username }}</h2>
<p>
팔로워: {{ member.followers.count }}명
팔로잉: {{ member.following.count }}명
</p>
</div>
<div>
<form action="{% url 'users:follow' member.pk %}" method="POST">
{% csrf_token %}
{% if user in member.followers.all %}
<button type="submit">언팔로우</button>
{% else %}
<button type="submit">팔로우</button>
{% endif %}
</form>
</div>
<a href="/index/">홈으로 돌아가기</a>
{% endblock content %}
최종 articles/templates/articles/article.html
좋아요
기능은ManyToManyField
를 사용하면 간편하게 구현 가능팔로우
기능은ManyToManyField('self', symmetrical=False)
로 구현 가능- Django ORM을 활용하면 M:N 관계의 데이터 처리 및 조회가 매우 직관적이고 간단해짐
add()
,remove()
메서드를 활용하여 관계를 쉽게 조작 가능
'∟ Framework > ⊢ Django' 카테고리의 다른 글
Django - Bootstrap, FontAwesome 활용 (1) | 2025.02.27 |
---|---|
Django - Custom User Model (0) | 2025.02.24 |
Django - 1:N 관계 (Many-to-One Relationships) (1) | 2025.02.20 |
Django - Admin Site 활용 (1) | 2025.02.13 |
Django - Static & Media (2) | 2025.02.08 |