각 회원의 개인 프로필 페이지에 팔로우 기능을 구현하기 위해 프로필 페이지를 먼저 구현하기
url
from django.urls import path
from . import views
app_name = 'accounts'
urlpatterns = [
path('login/', views.login, name='login'),
path('logout/', views.logout, name='logout'),
path('signup/', views.signup, name='signup'),
path('delete/', views.delete, name='delete'),
path('update/', views.update, name='update'),
path('profile/<username>/', views.profile, name='profile')
]
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)
profile.html
<h1> {{ person.username }}님의 프로필</h1>
<hr>
<h2>{{ person.username }} 가 작성한 게시글</h2>
{% for article in person.artilce_set.all %}
<div>{{ article.title }} </div>
{% endfor %}
<hr>
<h2> {{person.username }} 가 좋아요한 게시글</h2>
{% for article in person.like_artilces.all %}
<div>{{ article.title }} </div>
{% endfor %}
index.html
<a href="{% url 'accounts:profile' user.username %}"> 내 프로필</a>
<p>작성자 : <a href="{% url 'accounts:profile' article.user.username %}">{{ article.user }}</a>
</p>
0명 이상의 회원은 0명 이상의 회원과 관련
ManyToManyField 작성
# accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
followings = models.ManyToManyField('self', symmetrical=False, related_name='followers')
참조
역참조
바뀌어도 상관없으나 관계 조회 시 생각하기 편한 방향으로 정한 것
urls.py
# accounts/urls.py
urlpatterns = [
path('<int:user_pk>/follow/', views.follow, name='follow'),
]
views.py
# accounts/views.py
@login_required
def follow(request, user_pk):
User = get_user_model()
person = User.objects.get(pk=user_pk)
if person != request.user:
if request.user in person.followers.all():
person.followers.remove(request.user)
else:
person.followers.add(request.user)
return redirect('accounts:profile', person.username)
profile.html
<div>
팔로잉 : {{ person.followings.all|length }} / 팔로워 : {{ person.followers.all|length }}
</div>
{% if request.user != person %}
<div>
<form action="{% url "accounts:follow" person.pk %}" mehtod = "POST">
{% csrf_token %}
{% if request.user in person.followers.all %}
<input type="sumbit" value="Unfollow">
{% else %}
<input type="sumbit" value="follow">
{% endif %}
</form>
</div>
{% endif %}
python manage.py loaddata users.json
python manage.py loaddata articless.json
python manage.py loaddata comments.json# 3개의 모델을 하나의 json 파일로
python manage.py dumpdata --indent 4 articles.article articles.commnet accounts.user > data.json
# 모든 모델을 하나의 json 파일로
python manage.py dumpdata --indent 4 > data.json
PS. Fixtures 파일을 직접 만들지 말 것
SQL의 GROUP BY를 사용
각 게시글마다 댓글 개수를 반복 평가
문제 원인
<p> 댓글 개수 : {{ article.comment_set.count }}</p>
문제 해결
게시글을 조회하면서 댓글 개수까지 한번에 조회해서 가져오기
# views.py
def index_1(request):
# artilces = Article.objects.order_by('-pk')
articles = Article.objects.annotate(Count('comment')).order_by('-pk')
context = {
'articles' : articles,
}
return render(request, 'articles/index_1.html', context)
SQL의 INNER JOIN를 사용
문제 원인
{% for article in articles %}
<h3>작성자 : {{ article.user.username }}</h3>
<p>제목 : {{ article.title }} </p>
<hr>
{% endfor %}
문제 해결
11 queries including 10 simialar and 8 duplicates -> 1 query
# views.py
def index_2(request):
# artilces = Article.objects.order_by('-pk')
articles = Article.objects.select_related('user').order_by('-pk')
context = {
'articles' : articles,
}
return render(request, 'articles/index_2.html', context)
M:N 또는 N:1 역참조 관계에서 사용
문제 원인
{% for article in articles %}
<p> 제목 : {{ article.title }} </p>
<p> 댓글 목록</p>
{% for comment in article.comment_set.all %}
<p> {{ comment.content }} </p>
{% endfor %}
<hr>
{% endfor %}
문제 해결
게시글을 조회하면서 참조된 댓글까지 한번에 조회해서 가져오기
11 queries including 10 simialar -> 2 queries
# views.py
def index_3(request):
# artilces = Article.objects.order_by('-pk')
articles = Article.objects.prefetch_related('comment_set').order_by('-pk')
context = {
'articles' : articles,
}
return render(request, 'articles/index_3.html', context)
{% for article in articles %}
<p> 제목 : {{ article.title }} </p>
<p> 댓글 목록</p>
{% for comment in article.comment_set.all %}
<p> {{ comment.user.username }} : {{ comment.content }} </p>
{% endfor %}
<hr>
{% endfor %}
# views.py
def index_4(request):
# artilces = Article.objects.order_by('-pk')
articles = Article.objects.prefetch_related('comment_set').order_by('-pk')
context = {
'articles' : articles,
}
return render(request, 'articles/index_4.html', context)
- 2. 게시글 + 각 게시글의 댓글 목록 + 댓글의 작성자를 한번에 조회
# views.py
def index_4(request):
# artilces = Article.objects.order_by('-pk')
# articles = Article.objects.prefetch_related('comment_set').order_by('-pk')
articles = Article.objects.prefetch_related(Prefetch('comment_set', queryset=Comment.objects.select_related('user'))).order_by('-pk')
context = {
'articles' : articles,
}
return render(request, 'articles/index_4.html', context)