구독 기능, subscribe 기능을 RedirectView 라는 것을 만들어서 구현.
구독을 할떈 따로 구독 정보를 입력하는 것이 아니기 떄문에 form 으로 입력창을 보여줄만한 그런 중간 과정이 필요가 없음.
따라서 바로 요청을 받자마자 처리할 것 처리하고, redirect 하기 위해서 RedirectView 를 만들어볼 것.
app 시작
python manage.py startapp subscribeapp
settings.py -> subscribeapp 등록
urls.py -> path('subscribe/', include('subscribeapp.urls'))
subscribeapp -> urls.py 생성
from django.urls import path
app_name = 'subscribeapp'
urlpatterns = [
]
views.py 작성
views.py 작성
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import RedirectView
@method_decorator(login_required, 'get')
class SubscriptionView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
# detail 안아서 구독 버튼을 누를 수 있도록 하기 위해 되 돌아갈 곳은 projectapp 에서 detail 페이지
# project_pk 를 get 방식으로 보내어 해당 'pk' 를 가지고 있는 detail 페이지로 되돌아가기
return reverse('projectapp:detail', kwargs={'pk' : self.request.GET.get('project_pk')})
def get(self, request, *args, **kwargs):
return super(SubscriptionView, self).get(request, *args, **kwargs)
모델 작성
view 내용을 채우기 전에 model 작성 후 migration 작업
from django.contrib.auth.models import User
from django.db import models
from projectapp.models import Project
class Subscription(models.Model):
# 유저 연결
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='subscription')
# 프로젝트 연결
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='subscription')
class Meta: # Meta 정보로 넘겨주기
# 어떤 유저와 어떤 프로젝트 그 쌍이 가지는 구독 정보가 단 하나가 되도록 설정.
unique_together = ('user', 'project')
구독 기능 구현
이후 subscribeapp/views.py 마저 작성하기
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import RedirectView
from projectapp.models import Project
from subscribeapp.models import Subscription
@method_decorator(login_required, 'get')
class SubscriptionView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
# detail 안아서 구독 버튼을 누를 수 있도록 하기 위해 되 돌아갈 곳은 projectapp 에서 detail 페이지
# project_pk 를 get 방식으로 보내어 해당 'pk' 를 가지고 있는 detail 페이지로 되돌아가기
return reverse('projectapp:detail', kwargs={'pk' : self.request.GET.get('project_pk')})
def get(self, request, *args, **kwargs):
# 프로젝트와 유저정보를 취합하기 부분 추가 (get_object_or_404 라는 단축함수 사용하여 예외처리)
# project_pk 를 가지고 있는 Project 를 찾는데,
# 그게 만약 없다면(없는 프로젝트에 대한 구독의 경우) '페이지를 찾을 수 없음' 을 되돌려주도록
project = get_object_or_404(Project, pk=self.request.GET.get('project_pk'))
user = self.request.user # user 찾기
# user, project 가 각각 우리가 앞서 찾은 user, project 인 구독정보를 찾기
subscription = Subscription.objects.filter(user=user,
project=project)
if subscription.exists(): # 구독 정보가 존재한다면, 지우기
subscription.delete()
else: # 구독 정보가 존재하지 않는다면
Subscription(user=user, project=project).save() # -> 앞서 찾은 user,project 로 구독정보를 만들어야함.
# 대문자 S
return super(SubscriptionView, self).get(request, *args, **kwargs)
구독 버튼 만들어주기
버튼 자체는 로그인을 한 사람들에게만 보이도록 하기 위해 if 문 작성
우리가 만들었던 'subscribeapp:subscribe' 로 향하는 url 을 만들어 주고
뷰단에서 get 방식으로 project_pk 라는 데이터를 넘겨주기 떄문에
추가로 url 뒤에 get 방식으로 project_pk 에다가 현재 target_project 의 pk 를 넣어서 전송
{% extends 'base.html' %}
{% block content %}
<!-- 구독 버튼 -->
<div class="text-center mb-5" >
{% if user.is_authenticated %}
<a href="{% url 'subscribeapp:subscribe' %}?project_pk={{ target_project.pk }}"
class="btn btn=primary rounded-pill px-3"> <!-- 버튼 스타일 바꾸기-->>
Subscribe
</a>
{% endif %}
</div>
<!-- 게시글 보여주기 부분 -->
</div>
{% include 'snippets/list_fragment.html' with article_list=object_list %}
<div>
{% endblock %}
SubscribeView 작성 완료 후 subscribeapp 안의 url 등록
from django.urls import path
from subscribeapp.views import SubscriptionView
app_name = 'subscribeapp'
urlpatterns = [
path('subscribe/', SubscriptionView.as_view(), name='subscribe')
]
구독 버튼이 생성됨. 하지만 구독 버튼을 눌렀을때의 어떠한 변화도 없음. -> projectapp 의 detailview 수정
지금 접속해 있는 유저가 이 게시판(project) 에 대한 구독 정보가 있는지 없는지를 확인하는 작업이 필요함
/projectapp/views.py 수정
class ProjectDetailView(DetailView, MultipleObjectMixin):
model = Project
context_object_name = 'target_project'
template_name = 'projectapp/detail.html'
paginate_by = 25
def get_context_data(self, **kwargs):
project = self.object # object : 현재 project 페이지
user = self.request.user
# 유저가 로그인을 했는지 안했는지 확인
if user.is_authenticated: # 유저가 접속이 되있다면, usr 와 project 가 각각 user, project 인 구독정보를 찾고
subscription = Subscription.objects.filter(user=user, project=project)
# 유저가 접속되어있지 않는다면 구독 버튼 자체가 없기 떄문에 else 구문은 생략
object_list = Article.objects.filter(project=self.get_object())
# 최종적으로 템플릿으로 넘어갈때는 context_data 안에다가 구독 정보를 우리가 찾은 'subsriptiom' 으로 대체
# 이런식으로 구독 정보가 있는지 없는지 확인
return super(ProjectDetailView, self).get_context_data(object_list=object_list,
subscription=subscription,
**kwargs)
template 수정
/projectapp/templates/projectapp/detail.html 에서 사용자 인증과정을 통해 구독을 할때 안할때를 구분하여, '구독' '구독하지 않음' 버튼을 따로 설정.
<div class="text-center mb-5"> <!-- mb-5 : margin-bottom -->
{% if user.is_authenticated %}
{% if not subscription %} <!-- 구독이 아닐떄 구독 버튼을 보여주기-->
<a href="{% url 'subscribeapp:subscribe' %}?project_pk={{ target_project.pk }}"
class="btn btn-primary rounded-pill px-3"> <!-- 버튼 스타일 바꾸기-->
Subscribe
</a>
{% else %} <!-- 구독이 아닐때, 구독 취소 버튼-->
<a href="{% url 'subscribeapp:subscribe' %}?project_pk={{ target_project.pk }}"
class="btn btn-dark rounded-pill px-3"> <!-- 버튼 스타일 바꾸기-->
Unsubscribe
</a>
{% endif %}
{% endif %}
</div>
결과
구독 후
구독취소 후