• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

태그 작성 오류

21.10.14 20:59 작성 조회수 251

1

test진행시 마지막 단계에서 이런 오류 문구가 떠서 강사님과 똑같이 오류수정 진행하는데 해결이 되질 않습니다 ㅠ

혹시 몰라 views.py 와 test.py를 첨부해드리겠습니다.

from django.core.exceptions import PermissionDenied
from django.shortcuts import render, redirect
from django.utils.text import slugify
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from blog.models import Post, Category, Tag


class PostList(ListView):
    model = Post
    ordering = '-pk'

    def get_context_data(self, **kwargs):
        context = super(PostList, self).get_context_data()
        context['categories'] = Category.objects.all()
        context['no_category_post_count'] = Post.objects.filter(category=None).count()
        return context


class PostDetail(DetailView):
    model = Post

    def get_context_data(self, **kwargs):
        context = super(PostDetail, self).get_context_data()
        context['categories'] = Category.objects.all()
        context['no_category_post_count'] = Post.objects.filter(category=None).count()
        return context


class PostCreate(LoginRequiredMixin, UserPassesTestMixin,CreateView):  # LoginRequiredMixin 로그인이 되어 있는 경우에만 이 페이지 접속 가능하게
    model = Post
    fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']

    def test_func(self):
        return self.request.user.is_superuser or self.request.user.is_staff

    def form_valid(self, form):  # 폼에 들어있는 내용이 맞는지 확인하는 기능
        current_user = self.request.user
        if current_user.is_authenticated and (current_user.is_staff or current_user.is_superuser):
            form.instance.author = current_user  # 만들어진 Form에  instance의 author라는 필드를 current_user 로 채워라
            response = super(PostCreate, self).form_valid(form)  # from_valid() : 양식이 유효한경우 관련 모델을 저장.

            tags_str = self.request.POST.get('tags_str')
            if tags_str:
                tags_str = tags_str.strip()  # strip : 문자열 앞뒤에 빈공간 있으면 없애준다.
                tags_str = tags_str.replace(',', ';')  # 문자열 바꿔주기 , > ;
                tags_list = tags_str.split(';')  # 

                for t in tags_list:
                    t = t.strip()
                    tag, is_tag_created = Tag.objects.get_or_create(name=t)  # get_or_create(name=t) : 만약, name 이 t인 것을 가져오고, 없으면 그것을 name이 t로 만들어서 가져오기.
                    if is_tag_created:
                        tag.slug = slugify(t, allow_unicode=True)
                        tag.save()
                    self.object.tags.add(tag)
            return response
        else:
            return redirect('/blog/')  # 로그인을 하지 않고 해당 페이지를 열려하면 Blog 경로로 날려짐


class PostUpdate(LoginRequiredMixin, UpdateView):
    model = Post
    fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']
    template_name = 'blog/post_update_form.html'

    def dispatch(self, request, *args, **kwargs):  # 디스패치라는것은 url을 get 방식인지 post방식인지 알아내는 방법이지만, 해당 하는 포스트에 권한이 있는 유저인지 검증할 수 있다.
        if request.user.is_authenticated and request.user == self.get_object().author:
            return super(PostUpdate, self).dispatch(request, *args, **kwargs)
        else:
            raise PermissionDenied  # 장고에서 기본으로 제공되는 기능이고, 에러 페이지 대신에 권한이 없다면 권한이 없다는 메시지를 띄어준다

    def get_context_data(self, **kwargs):
        context = super(PostUpdate, self).get_context_data()
        if self.object.tags.exists():
            tags_str_list = list()
            for t in self.object.tags.all():
                tags_str_list.append(t.name)
            context['tags_str_default'] = '; '.join(tags_str_list)
        return context

    def form_valid(self, form):
        response = super(PostUpdate, self).form_valid(form)
        self.object.tags.clear()

        tags_str = self.request.POST.get('tags_str')
        if tags_str:
            tags_str = tags_str.strip()  # strip : 문자열 앞뒤에 빈공간 있으면 없애준다.
            tags_str = tags_str.replace(',', ';')  # 문자열 바꿔주기 , > ;
            tags_list = tags_str.split(';')  #

            for t in tags_list:
                t = t.strip()
                tag, is_tag_created = Tag.objects.get_or_create(name=t)  # get_or_create(name=t) : 만약, name 이 t인 것을 가져오고, 없으면 그것을 name이 t로 만들어서 가져오기.
                if is_tag_created:
                    tag.slug = slugify(t, allow_unicode=True)
                    tag.save()
                self.object.tags.add(tag)
        return response


def category_page(request, slug):
    if slug == 'no_category':
        category = '미분류'
        post_list = Post.objects.filter(category=None)
    else:
        category = Category.objects.get(slug=slug)
        post_list = Post.objects.filter(category=category)

    return render(
        request,
        'blog/post_list.html',
        {
            'post_list': post_list,
            'categories': Category.objects.all(),
            'no_category_post_count': Post.objects.filter(category=None).count(),
            'category': category
        }

    )


def tag_page(request, slug):
    tag = Tag.objects.get(slug=slug)
    post_list = tag.post_set.all()

    return render(
        request,
        'blog/post_list.html',
        {
            'post_list': post_list,
            'categories': Category.objects.all(),
            'no_category_post_count': Post.objects.filter(category=None).count(),
            'tag': tag
        }

    )

# def single_post_page(request, pk): # reqeust, 변수명
#     post = Post.objects.get(pk=pk)
#
#     return render(
#         request,
#         'blog/single_page.html',
#         {
#             'post': post,
#         }
#     )


## 이건 test.py 코드입니다##################




from django.test import TestCase, Client  # Client 가 하는 역할 : 장고에서 재공하는 것이며 웹사이트의 방문자를 말함?
from bs4 import BeautifulSoup
from .models import Post, Category, Tag
from django.contrib.auth.models import User  # 장고에서 기본적으로 제공하는 User 임.


class TestView(TestCase):
    def setUp(self):  # DB에 들어갈 내용을 여기서 테스트 적용
        self.client = Client()
        self.user_trump = User.objects.create_user(
            username='trump',
            password='somepassword',
        )
        self.user_obama = User.objects.create_user(
            username='obama',
            password='somepassword',
        )
        self.user_obama.is_staff = True
        self.user_obama.save()

        self.category_programming = Category.objects.create(
            name='programming', slug='programming'
        )
        self.category_music = Category.objects.create(
            name='music', slug='music'
        )
        self.tag_python_kor = Tag.objects.create(
            name='파이썬 공부', slug='파이썬-공부'
        )
        self.tag_python = Tag.objects.create(
            name='python', slug='python'
        )
        self.tag_hello = Tag.objects.create(
            name='hello', slug='hello'
        )

        self.post_001 = Post.objects.create(
            title='첫번째 포스트 입니다.',
            content='Hello, World. we are the World',
            category=self.category_programming,
            author=self.user_trump
        )
        self.post_001.tags.add(self.tag_hello)

        self.post_002 = Post.objects.create(
            title='두번째 포스트 입니다.',
            content='저는 쌀국수를 좋아합니다.',
            category=self.category_music,
            author=self.user_obama
        )
        self.post_003 = Post.objects.create(
            title='세번째 포스트 입니다.',
            content='Category가 없나유.',
            author=self.user_obama
        )
        self.post_003.tags.add(self.tag_python)
        self.post_003.tags.add(self.tag_python_kor)

    def navbar_test(self, soup):
        navbar = soup.nav
        self.assertIn('Blog', navbar.text)
        self.assertIn('About Me', navbar.text)

        logo_btn = navbar.find('a', text='Saohwan')
        self.assertEqual(logo_btn.attrs['href'], '/')

        home_btn = navbar.find('a', text='Home')
        self.assertEqual(home_btn.attrs['href'], '/')

        blog_btn = navbar.find('a', text='Blog')
        self.assertEqual(blog_btn.attrs['href'], '/blog')

        about_me_btn = navbar.find('a', text='About Me')
        self.assertEqual(about_me_btn.attrs['href'], '/about_me')

    def category_card_test(self, soup):
        categories_card = soup.find('div', id='categories-card')
        self.assertIn('Categories', categories_card.text)  # 카테고리스라는 문구가 categories_card 에 있는지 확인하는 테스트
        self.assertIn(
            f'{self.category_programming} ({self.category_programming.post_set.count()})',
            categories_card.text
        )
        self.assertIn(
            f'{self.category_music} ({self.category_music.post_set.count()})',
            categories_card.text
        )  # 이렇게 하는 이유는 유지 보수성을 위해
        self.assertIn(
            f'미분류 ({Post.objects.filter(category=None).count()})',
            categories_card.text
        )

    def test_post_list_with_posts(self):
        self.assertEqual(Post.objects.count(), 3)  # 시작하자마자 포스트가 3개있다.

        # 1.1 포스트 목록 페이지 (post list)를 연다.
        response = self.client.get('/blog/')  # 블로그 페이지가서 읽고
        # 1.2 정상적으로 페이지가 로드된다.
        self.assertEqual(response.status_code, 200)  # 에러 코드가 200이면 정상임
        # 1.3 페이지의 타이틀에 Blog 라는 문구가 있다.
        soup = BeautifulSoup(response.content, 'html.parser')

        self.assertIn('Blog', soup.title.text)  # soup.title.text에 'blog' 라는 문구가 있어야한다. soup 으로 접근

        self.navbar_test(soup)  # 블로그라는게 헤더 타이틀에 있는지 확인\
        self.category_card_test(soup)

        # 3.3 메인 영역에 포스트 2개의 타이틀이 존재한다.
        main_area = soup.find('div', id='main-area')
        # 3.4 "아직 게시물이 없습니다" 라는 문구가 없어야 한다.
        self.assertNotIn('아직 게시물이 없습니다.', main_area.text)

        post_001_card = main_area.find('div', id='post-1')
        self.assertIn(self.post_001.title, post_001_card.text)
        self.assertIn(self.post_001.category.name, post_001_card.text)
        self.assertIn(self.tag_hello.name, post_001_card.text)
        self.assertNotIn(self.tag_python.name, post_001_card.text)
        self.assertNotIn(self.tag_python_kor.name, post_001_card.text)

        post_002_card = main_area.find('div', id='post-2')
        self.assertIn(self.post_002.title, post_002_card.text)
        self.assertIn(self.post_002.category.name, post_002_card.text)
        self.assertNotIn(self.tag_hello.name, post_002_card.text)
        self.assertNotIn(self.tag_python.name, post_002_card.text)
        self.assertNotIn(self.tag_python_kor.name, post_002_card.text)

        post_003_card = main_area.find('div', id='post-3')
        self.assertIn(self.post_003.title, post_003_card.text)
        self.assertIn('미분류', post_003_card.text)
        self.assertNotIn(self.tag_hello.name, post_003_card.text)
        self.assertIn(self.tag_python.name, post_003_card.text)
        self.assertIn(self.tag_python_kor.name, post_003_card.text)

        self.assertIn(self.post_001.author.username.upper(), main_area.text)
        self.assertIn(self.post_002.author.username.upper(), main_area.text)  # upper 대문자로 나왔으면 좋겠을 때.

    def test_post_list_without_posts(self):
        Post.objects.all().delete()

        response = self.client.get('/blog/')
        self.assertEqual(response.status_code, 200)  # 에러 코드가 200이면 정상임

        soup = BeautifulSoup(response.content, 'html.parser')
        self.navbar_test(soup)
        self.assertIn('Blog', soup.title.text)

        self.assertEqual(Post.objects.count(), 0)  # Post 모델에 레코드가 몇개 있는지 아무 겄도 없을때

        main_area = soup.find('div', id='main-area')
        self.assertIn('아직 게시물이 없습니다.', main_area.text)

    def test_post_detail(self):
        self.assertEquals(Post.objects.count(), 3)  # 테스트는 생성할때마다 DB가 초기화되서 0이다.
        # 1.2 그 포스트의 url은 '/blog/1/' 이다.
        self.assertEquals(self.post_001.get_absolute_url(), '/blog/1/')

        # 2 첫 번째 포스트의 상세 페이지 테스트
        # 2.1 첫 번쨰 포스트의 url로 접근하면 정상적으로 response가 온다..(status code: 200).
        response = self.client.get(self.post_001.get_absolute_url())
        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content, 'html.parser')
        # 2.2 포스트 목록 페이지와 똑같은 내비게이션 바가 있다.
        self.navbar_test(soup)
        self.category_card_test(soup)

        # 2.3 첫 번째 포스트의 제목이 웹 브라우저 탭 타이틀에 들어 있다.
        self.assertIn(self.post_001.title, soup.title.text)
        # 2.4 첫 번째 포스트의 제목이 포스트 영역에 있다.
        main_area = soup.find('div', id='main-area')
        post_area = main_area.find('div', id='post-area')
        self.assertIn(self.post_001.title, post_area.text)
        self.assertIn(self.post_001.category.name, post_area.text)
        # 2.5 첫 번째 포스트의 작성자(author)가 포스트 영역에 있다.(아직 구현할 수 없음).
        self.assertIn(self.user_trump.username.upper(), main_area.text)
        # 2.6 첫 번째 포스트의 내용(content)이 포스트 영역에 있다.
        self.assertIn(self.post_001.content, post_area.text)

    def test_category_page(self):
        response = self.client.get(self.category_programming.get_absolute_url())
        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content, 'html.parser')  # html.parser 로 담아준다.
        self.navbar_test(soup)
        self.category_card_test(soup)

        main_area = soup.find('div', id='main-area')
        self.assertIn(self.category_programming.name, main_area.h1.text)
        self.assertIn(self.category_programming.name, main_area.text)
        self.assertIn(self.post_001.title, main_area.text)
        self.assertNotIn(self.post_002.title, main_area.text)
        self.assertNotIn(self.post_003.title, main_area.text)

    def test_tag_page(self):
        response = self.client.get(self.tag_hello.get_absolute_url())
        self.assertEqual(response.status_code, 200)
        soup = BeautifulSoup(response.content, 'html.parser')

        self.navbar_test(soup)
        self.category_card_test(soup)

        self.assertIn(self.tag_hello.name, soup.h1.text)
        main_area = soup.find('div', id='main-area')
        self.assertIn(self.tag_hello.name, main_area.text)

        self.assertIn(self.post_001.title, main_area.text)
        self.assertNotIn(self.post_002.title, main_area.text)
        self.assertNotIn(self.post_003.title, main_area.text)

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

    def test_create_post_with_login(self):
        self.client.login(username='trump', password='somepassword')
        response = self.client.get('/blog/create_post/')
        self.assertNotEqual(response.status_code, 200)

        self.client.login(username='obama', 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 a New Post', main_area.text)

        tags_str_input = main_area.find('input', id='id_tags_str') # input 이라는 태그중에서 id가 id_tags_str 이 있는지 확인하는 작업.
        self.assertTrue(tags_str_input)
        self.assertEqual(Tag.objects.count(), 3)

        self.client.post(
            '/blog/create_post/',
            {
                'title': 'Post Form 만들기',
                'content': 'Post Form 페이지를 만듭시다.',
                'tags_str': 'new_tag; 한글 태그, python'
            }
        )

        last_post = Post.objects.last()
        self.assertEqual(last_post.title, 'Post Form 만들기')
        self.assertEqual(last_post.author.username, 'obama')
        self.assertEqual(last_post.content, 'Post Form 페이지를 만듭시다.')

        self.assertEqual(last_post.tags.count(), 3)
        self.assertTrue(Tag.objects.get(name='new_tag'))
        self.assertTrue(Tag.objects.get(name='한글 태그'))
        self.assertTrue(Tag.objects.get(name='python'))
        self.assertEqual(Tag.objects.count(), 5)

    def test_update_post(self):
        update_post_url = f'/blog/update_post/{self.post_003.pk}/'

        # 로그인 하지 않은 상태에서 접근 하는 경우
        response = self.client.get(update_post_url)
        self.assertNotEqual(response.status_code, 200)

        # 로그인은 했지만, 작성자가 아닌 경우
        self.assertNotEqual(self.post_003.author, self.user_trump)
        self.client.login(usernmae='trump', password='somepassword')
        response = self.client.get(update_post_url)
        self.assertNotEqual(response.status_code, 200)

        # 작성자(obama)가 접근하는 경우
        self.assertEqual(self.post_003.author, self.user_obama)
        self.client.login(username='obama', password='somepassword')
        response = self.client.get(update_post_url)
        self.assertEqual(response.status_code, 200)
        soup = BeautifulSoup(response.content, 'html.parser')

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

        tag_str_input = main_area.find('input', id='id_tags_str')
        self.assertTrue(tag_str_input)
        self.assertIn('파이썬 공부; python', tag_str_input.attrs['value'])

        response = self.client.post(
            update_post_url,
            {
                'title': '세 번째 포스트를 수정했습니다.',
                'content': '안녕 세계? 우리는 하나!',
                'category': self.category_music.pk,
                'tags_str': '파이썬 공부; 한글 태그, some tag'
            },
            follow=True  # 위 내용을 리다이렉트 되는 것을 따라가려면 설정
        )
        soup = BeautifulSoup(response.content, 'html.parser')
        main_area = soup.find('div', id='main-area')
        self.assertIn('세 번째 포스트를 수정했습니다.', main_area.text)
        self.assertIn('안녕 세계? 우리는 하나!', main_area.text)
        self.assertIn(self.category_music.name, main_area.text)
        
        self.assertIn('파이썬 공부', main_area.text)
        self.assertIn('한글 태그', main_area.text)
        self.assertIn('some tag', main_area.text)
        self.assertNotIn('python', main_area.text)

답변 1

답변을 작성해보세요.

0

test_update_post 함수에서 

# 로그인은 했지만, 작성자가 아닌 경우
self.assertNotEqual(self.post_003.author, self.user_trump)
self.client.login(usernmae='trump', password='somepassword')

마지막 줄에 username이 아니고 usernmae로 돼 있네요.

 

오타로 인한 오류 같습니다.

 

 

Cooper Ben님의 프로필

Cooper Ben

질문자

2021.10.16

해당 오타부분을 고쳤지만 똑같이 295번째인 

test 실행시 self.assertIn('파이썬 공부', main_area.text) 가 오류라고 지정이됩니다.! 

 

다른 문제점이 있을까요?