Subscribeapp 구현

jurin·2021년 11월 8일
0

Django Project - LeeBook

목록 보기
9/11

RedirectView

구독 버튼을 누르면 그 페이지에서 다른 페이지로 넘어가는 게 아닌 구독 버튼만 바뀐다. 별 다른 정보를 넘겨주지도 않는다. 요청을 받자마자 처리할 것들을 하고 바로 Redirect하도록 한다.

startapp subscribeapp

LeeBook의 settings.py, urls.py 추가

subscribeapp urls.py 생성 후 app_name 설정

Model 코딩

같은 게시판을 여러번 구독할 수 없으므로 user과 project를 연결하는 쌍이 가지는 구독 정보가 하나여야 한다.

Meta 정보로 unique_together를 이용하여 둘을 한 쌍으로 묶어준다.

from django.contrib.auth.models import User
from django.db import models

# Create your models here.
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:
        unique_together = ('user', 'project')

model 작업을 했으므로 makemigration, migrate를 해준다.

View 코딩

get_redirect_url 메소드를 이용해 projectapp:detail로 향하게 한다.
GET방식으로 project_pk를 받아서 이 pk를 가지고 있는 detail 페이지로 돌아가는 것이다.

project: get_object_or_404 단축함수를 이용해 project_pk를 가지고 있는 Project를 찾는데 없다면 404 반응을 낸다.
user: self.request.user

project, user 두 정보를 찾아낸 후 subscription을 찾는다.
만약 있다면 삭제해주고 없다면 만들고 저장해준다.

@method_decorator(login_required, 'get')
class SubscriptionView(RedirectView):

    def get_redirect_url(self, *args, **kwargs):
        return reverse('projectapp:detail', kwargs={'pk': self.request.GET.get('project_pk')})


    def get(self, request, *args, **kwargs):
        project = get_object_or_404(Project, pk=self.request.GET.get('project_pk'))
        user= self.request.user

        subscription = Subscription.objects.filter(user=user,
                                                   project=project)

        # 구독했으면 없애고 안했으면 해주고
        if subscription.exists():
            subscription.delete()
        else:
            Subscription(user=user, project=project).save()

        return super(SubscriptionView, self).get(request, *args, **kwargs)
    

subscribe/ url 추가

from django.urls import path

from subscribeapp.views import SubscriptionView

app_name = 'subscribeapp'

urlpatterns = [
    path('subscribe/', SubscriptionView.as_view(), name='subscribe')
]

구독 버튼

projectapp/detail.html

SubscriptionView에서 GET방식으로 project_pk라는 데이터를 넘겨주기로 했으니까 detail에서 target_project.pk를 project_pk로 넘겨준다.

        <a href="{% url 'subscribeapp:subscribe'%}?project_pk={{ target_project.pk }}"
           class="btn btn-primary rounded-pill px-4">
        </a>

이렇게 하면 작동은 되지만 구독을 했는지 안했는지 알 방법이 없다.

projectapp/views.py의 DetailView에서 지금 접속한 유저이 이 게시판에 대해 구독 정보가 있는 지 없는지 확인을 해주는 작업이 필요하다.

get_context_data 안에서 현재 project와 user 정보를 얻어온다. 그런데 여기서 그 user가 로그인을 했는지 안했는 지 확인하는 작업부터 해줘야 한다.

유저가 로그인이 되어 있으면 subscription 변수에 얻어온 user와 project를 넣어줘서 찾아준다. 그 후 찾은 subscription을 return 해준다.

    def get_context_data(self, **kwargs):
        project = self.object
        user= self.request.user

        # user의 로그인 여부
        if user.is_authenticated:
            subscription = Subscription.objects.filter(user=user, project=project)

        object_list = Article.objects.filter(project=self.get_object())
        return super(ProjectDetailView, self).get_context_data(object_list=object_list,
           

detail에서 토글이 되는 것을 눈으로 확인할 수 있도록 수정해준다.

<!--구독버튼-->
    <div class="text-center mb-5">
        {% if user.is_authenticated %}
            {% if not subscription %}
            <a href="{% url 'subscribeapp:subscribe'%}?project_pk={{ target_project.pk }}"
               class="btn btn-primary rounded-pill px-4">
                Subscribe
            </a>
            {% else %}
            <a href="{% url 'subscribeapp:subscribe'%}?project_pk={{ target_project.pk }}"
               class="btn btn-dark rounded-pill px-4">
                Unsubscribe
            </a>
            {% endif%}
        {% endif %}
    </div>

Field Lookup을 사용한 구독 페이지 구현

field를 사용할 때 다음과 같이 특정 조건을 넣는 형식으로 했었다.

Model.objects.filter(pk=xxx, user=xxx)

(pk=xxx, user=xxx)는 pk와 user 값의 AND function이다. 그렇다면 OR function, WHERE 구문은 어떻게 사용할까?

다음 작업을 진행하면서 알아보자

  1. Find user Subscripted projects.
    유저가 구독하고 있는 프로젝트들을 확인하기

  2. Find articles in projects.
    그 프로젝트 안 모든 게시글 가져오기

기존에 사용하던 방식에서 다음과 같이 바꾼다.

Model.objects.filter(project__in=projects)

이 project__in=projects같이 double underscore로 이루어진 것들이 장고에서 제공하는 field lookup이다.

SQL안에서 field lookup의 작동 방식

SELECT ... WHERE project IN (''');

목적 : 조금 더 복잡한 DB 쿼리를 사용자가 구현할 수 있도록 사용한다. For advanced DB query

종류

  • Model__exact
  • Model__iexact
  • Model__contains
  • Model__in
  • Model__gte
  • 등등

SubscriptionListView

특정 조건을 만족하는 게시글을 가져와야 하기 때문에 SubscriptionListView안에서 queryset 관련 함수를 새로 작성한다.

value_list('project')는 값들을 list화 시키는 함수인데 우리는 Subscription 모델에서 user와 project를 지정해줬다. 이 project에 대해 list화 시킨다는 것이다.

이제 여기서 field lookup을 사용해 article_list를 만든다.

@method_decorator(login_required, 'get')
class SubscriptionListView(ListView):
    model = Article
    context_object_name = 'article_list'
    template_name = 'subscribeapp/list.html'
    paginate_by = 5

    # 특정 조건을 만족하는 게시글을 가져와야 하기 때문에 queryset 관련 함수를 새로 작성한다.
    def get_queryset(self):
        # user가 구독하고 있는 프로젝트 찾기
        projects = Subscription.objects.filter(user=self.request.user).values_list('project')

        # 프로젝트 안 모든 게시글 가져오기
        article_list = Article.objects.filter(project__in=projects)
        return article_list

subscribe/list.html

이전에 list_fragment.html로 조각화해놓은 것을 그대로 가져온다.

{% extends 'base.html' %}

{% block content %}

    <div>
        {% include 'snippets/list_fragment.html' with article_list=article_list %}
    </div>

{% endblock%}

url 추가

    path('list/', SubscriptionListView.as_view(), name='list'),

Subscribe 버튼

header.html에서 버튼을 생성해준다.

            <a href="{% url 'subscribeapp:list' %}" class="leebook_header_nav">
                <span>Subscription</span>
            </a>
profile
anaooauc1236@naver.com

0개의 댓글