User 자기 자신과의 M:N 관계 설정을 통해 팔로우 기능을 구현해보자.
먼저 자연스러운 follow 흐름을 위해 프로필 페이지를 작성해보자.
# accounts/urls.py
from django.urls import path
from . import views
app_name = 'accounts'
urlpatterns = [
...,
path('profile/<username>/', views.profile, name='profile'),
]
# accounts/views.py
from django.contrib.auth import get_user_model
def profile(request, username):
User = get_user_model()
person = User.objects.get(username=username)
context = {
'person' : person,
}
return render(request, 'accounts/profile.html', context)
<!-- accounts/profile.html -->
{% extends 'base.html' %}
{% block content %}
<h1>{{ person.username }}님의 프로필</h1>
<hr>
<h2>{{ person.username }}'s 게시글</h2>
{% for article in person.article_set.all %}
<div>{{ article.title }}</div>
{% endfor %}
<hr>
<h2>{{ person.username }}'s 댓글</h2>
{% for comment in person.comment_set.all %}
<div>{{ comment.content }}</div>
{% endfor %}
<hr>
<h2>{{ person.username }}'s 좋아요한 게시글</h2>
{% for article in person.like_articles.all %}
<div>{{ article.title }}</div>
{% endfor %}
<hr>
<a href="{% url 'articles:index' %}">back</a>
{% endblock content %}
<!-- base.html -->
<body>
<div id="nav">
{% if user.is_authenticated %}
<a href="{% url 'accounts:logout' %}">로그아웃</a>
<a href="{% url 'accounts:update' %}">회원정보수정</a>
<!-- Profile 템플릿으로 이동할 수 있는 하이퍼 링크 작성 -->
<a href="{% url 'accounts:profile' user.username %}">내 프로필</a>
<form action="{% url 'accounts:delete' %}" method="POST">
{% csrf_token %}
<input type="submit" value="회원탈퇴">
</form>
<h3 id="user-hello"><i>안녕하세요, {{user}} 님 !</i></h3>
{% else %}
<a href="{% url 'accounts:signup' %}">회원가입</a>
<a href="{% url 'accounts:login' %}">로그인</a>
{% endif %}
</div>
<hr>
<div id="content">
{% block content %}{% endblock content %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
</body>
<!-- articles/index.html -->
{% extends 'base.html' %}
{% block content %}
<h1>INDEX</h1>
<a href="{% url 'articles:create' %}">작성하기</a>
<hr />
{% for article in articles %}
<p>
[{{article.id}}]
<a href="{% url 'articles:detail' article.pk %}" id="article-title">{{article.title}}</a>
<!-- Profile 템플릿으로 이동할 수 있는 하이퍼 링크 작성 -->
<b>- 작성자: <a href="{% url 'accounts:profile' article.user.username %}">{{article.user}}</a></b>
</p>
{% if request.user.is_authenticated %}
<div>
<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>
</div>def profile(request, username):
User = get_user_model()
person = User.objects.get(username=username)
context = {
'person' : person,
}
return render(request, 'accounts/profile.html', context)
{% endif %}
<hr />
{% endfor %}
{% endblock content %}
# accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
following = models.ManyToManyField('self', symmetrical=False, related_name='followers')
$ python manage.py makemigrations
$ python manage.py migrate
# accounts/urls.py
from django.urls import path
from . import views
app_name = 'accounts'
urlpatterns = [
...,
path('<int:user_pk>/follow/', views.follow, name='follow'),
]
# accounts/views.py
def follow(request, user_pk):
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.username)
<!-- accounts/profile.html -->
<h1>{{ person.username }}님의 프로필</h1>
<hr>
<div>
<div>
팔로잉 : {{ person.followings.all|length }} / 팔로워 : {{ person.followers.all|length }}
</div>
{% if request.user != person %}
<div>
<form action="{% url 'accounts:follow' person.pk %}" methon="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>
<!-- accounts/profile.html -->
{% extends 'base.html' %}
{% block content %}
<h1>{{ user.username }}님의 프로필</h1>
<div>
<div>팔로잉 : {{ user.followings.count }} | 팔로워 : {{ user.followers.count }}</div>
{% if request.user != user %}
<form action="{% url 'accounts:follow' user.pk %}" method="POST">
{% csrf_token %}
{% if request.user in user.followers.all %}
<button type="submit" class="btn btn-danger">언팔로우</button>
{% else %}
<button type="submit" class="btn btn-primary">팔로우</button>
{% endif %}
</form>
{% endif %}
</div>
<hr>
<h5>{{ user.username }}님의 작성글</h5>
<hr>
{% for article in user.article_set.all %}
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ article.title }}</h5>
<p class="card-text">{{ article.content }}</p>
<a href="{% url 'articles:detail' article.pk %}" class="btn btn-primary">자세히 보기</a>
</div>
</div>
{% endfor %}
<br><br>
<h5>{{ user.username }}님이 좋아요한 게시물</h5>
<hr>
{% for article in user.like_articles.all %}
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ article.title }}</h5>
<p class="card-text">{{ article.content }}</p>
<a href="{% url 'articles:detail' article.pk %}" class="btn btn-primary">자세히 보기</a>
</div>
</div>
{% endfor %}
<br><br>
<a href="{% url 'articles:index' %}" class="btn btn-success">목록보기</a>
{% endblock content %}
https://github.com/mjieun0956/TIL/tree/master/Database/07.%20User-User%20(Follow)