로그인한 방문자만 포스트를 작성할 수 있도록 만들기

Posted on 2021-08-25 by GKSRUDTN99
Django로 웹사이트 만들기 장고

테스트 코드 작성

# blog/tests.py

    def test_create_post(self):
        response = self.client.get('/blog/create_post/')
        self.assertNotEqual(response.status_code, 200)

        self.client.login(username='trump', password='somepassword')

        response = self.client.get('/blog/create_post/')
        self.assertEqual(response.status_code, 200)
        soup = BeautifulSoup(response.content, 'html.parser')

        self.assertEqual('Create Post - Blog', soup.title.text)
        main_area = soup.find('div', id='main-area')
        self.assertIn('Create New Post', main_area.text)

우선, 로그인 하지 않은 상태에서는 status_code가 200이 아니어야 한다.

로그인 하였다면, 기존과 같은 테스트를 진행하도록 한다.

로그인 테스트 유의사항

이전에 작성한 tests.py에서는 유저를 다음과 같은 코드로 생성한다.

self.user_trump = User.objects.create(username='trump', password='somepassword')

위와 같은 방법으로 유저를 생성할 경우, password 필드에 somepassword 문자열이 그대로 들어가게 된다.

하지만, 위의 경우처럼 client.login을 시도할 경우, password 필드에 somepassword를 입력하면, 장고는 somepassword를 해싱한 값을 DB와 비교한다.

하지만, DB에는 해싱된 값이 아닌 somepassword 문자열이 그대로 들어가 있으므로, 로그인이 정상적으로 동작하지 않는다.

위 문제를 해결하기 위해, 유저 생성 코드를 다음과 같이 수정한다.

self.user_trump = User.objects.create(username='trump')
self.user_trump.set_password('somepassword')
self.user_trump.save()

PostCreate 클래스에 LoginRequiredMixin 추가하기

PostCreate클래스에 매개변수로 LoginRequiredMixin 클래스를 추가하면 로그인했을 때만 정상적으로 페이지가 보이게 된다.

✔︎ Mixin은 확장하는 클래스 전에 적는다!
# blog/views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Post, Category, Tag

(...생략...)

class PostCreate(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']

테스트 코드 추가

테스트 코드에 포스트를 작성한 후 submit 버튼을 클릭하는 행위까지 구현한다.

# blog/tests.py
    def test_create_post(self):
        # 로그인 하지 않으면 status code가 200이면 안된다!
        response = self.client.get('/blog/create_post/')
        self.assertNotEqual(response.status_code, 200)

        # 로그인을 한다.
        self.client.login(username='trump', password='somepassword')

        response = self.client.get('/blog/create_post/')
        self.assertEqual(response.status_code, 200)
        soup = BeautifulSoup(response.content, 'html.parser')

        self.assertEqual('Create Post - Blog', soup.title.text)
        main_area = soup.find('div', id='main-area')
        self.assertIn('Create New Post', main_area.text)

        self.client.post(
            '/blog/create_post/',
            {
                'title': 'Post form 만들기',
                'content': "Post Form 페이지를 만듭시다.",
            }
        )
        last_post = Post.objects.last()
        self.assertEqual(last_post.title, "Post form 만들기")
        self.assertEqual(last_post.author.username, 'trump')

self.client.post()함수는 첫 번째 인수인 경로로 두 번째 인수인 딕셔너리 정보를 POST 방식으로 보낸다.

자동으로 author 필드 채우기

CreateView클래스에는 form_valid()함수가 정의되어 있다.

사용자가 내용을 입력한 뒤 전송하면 form_valid()함수가 호출된다.

form_valid()함수는 사용자가 폼에 담아 보낸 유효한 정보를 사용해 포스트를 만들고, 이 포스트를 고유 경로로 보내주는(redirect) 역할을 한다.

# blog/views.py
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Post, Category, Tag

(... 생략 ...)

class PostCreate(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']

    def form_valid(self, form):
        current_user = self.request.user
        if current_user.is_authenticated:
            form.instance.author = current_user
            return super(PostCreate, self).form_valid(form)
        else:
            return redirect('/blog/')

1. self.request.user로 사용자 객체를 받아온다.

2. is_authenticated로 사용자의 로그인 여부를 확인한다.

3. form의 author 필드에 current_user를 추가한다.

4. user가 추가된 폼을 CreateView의 기본 form_valid()의 인자로 보내어 처리한다.