تست ویوی بروزرسانی

سلام

درون فولدر boards/tests یک فایل با نام test_view_edit_post.py ایجاد می کنیم. قسمتی که باید تغییر کرده و اضافه شود به شکل زیر است.

boards/tests/test_view_edit_post.py (مشاهده کد کامل)

from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from ..models import Board, Post, Topic
from ..views import PostUpdateView

class PostUpdateViewTestCase(TestCase):
    '''
    Base test case to be used in all `PostUpdateView` view tests
    '''
    def setUp(self):
        self.board = Board.objects.create(name='Django', description='Django board.')
        self.username = 'john'
        self.password = '123'
        user = User.objects.create_user(username=self.username, email='john@doe.com', password=self.password)
        self.topic = Topic.objects.create(subject='Hello, world', board=self.board, starter=user)
        self.post = Post.objects.create(message='Lorem ipsum dolor sit amet', topic=self.topic, created_by=user)
        self.url = reverse('edit_post', kwargs={
            'pk': self.board.pk,
            'topic_pk': self.topic.pk,
            'post_pk': self.post.pk
        })

class LoginRequiredPostUpdateViewTests(PostUpdateViewTestCase):
    def test_redirection(self):
        '''
        Test if only logged in users can edit the posts
        '''
        login_url = reverse('login')
        response = self.client.get(self.url)
        self.assertRedirects(response, '{login_url}?next={url}'.format(login_url=login_url, url=self.url))

class UnauthorizedPostUpdateViewTests(PostUpdateViewTestCase):
    def setUp(self):
        '''
        Create a new user different from the one who posted
        '''
        super().setUp()
        username = 'jane'
        password = '321'
        user = User.objects.create_user(username=username, email='jane@doe.com', password=password)
        self.client.login(username=username, password=password)
        self.response = self.client.get(self.url)

    def test_status_code(self):
        '''
        A topic should be edited only by the owner.
        Unauthorized users should get a 404 response (Page Not Found)
        '''
        self.assertEquals(self.response.status_code, 404)


class PostUpdateViewTests(PostUpdateViewTestCase):
    # ...

class SuccessfulPostUpdateViewTests(PostUpdateViewTestCase):
    # ...

class InvalidPostUpdateViewTests(PostUpdateViewTestCase):
    # ...

فعلاً مهم ترین بخش PostUpdateViewTestCase به عنوان کلاسی است که برای استفاده چند باره میان سایر موارد تست تعریف شده است. این مورد شامل تنظیمات اولیه، ساخت کاربران، تاپیک ها، بوردها و… است.

کلاس LoginRequiredPostUpdateViewTests بررسی می کند که آیا ویوی مربوطه با دکوراتور login_required@ محافظت شده است یا خیر. همانطور که می دانید فقط کاربران معتبر امکان دسترسی به این صفحه را دارند.

کلاس UnauthorizedPostUpdateViewTests یک کاربر جدید ایجاد می کند. کاربری که با نویسنده و ایجاد کنندۀ پست متفاوت بوده و سپس تلاش می کند به قسمت ویرایش صفحه وارد شود. طبیعی است که برنامه فقط به کاربری اجازه تغییر و ویرایش پست را می دهد که آن پست توسط همان کاربر ایجاد شده باشد.

تست را اجرا می کنیم:

python manage.py test boards.tests.test_view_edit_post
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..F.......F
======================================================================
FAIL: test_redirection (boards.tests.test_view_edit_post.LoginRequiredPostUpdateViewTests)
----------------------------------------------------------------------
...
AssertionError: 200 != 302 : Response didn't redirect as expected: Response code was 200 (expected 302)

======================================================================
FAIL: test_status_code (boards.tests.test_view_edit_post.UnauthorizedPostUpdateViewTests)
----------------------------------------------------------------------
...
AssertionError: 200 != 404

----------------------------------------------------------------------
Ran 11 tests in 1.360s

FAILED (failures=2)
Destroying test database for alias 'default'...

اول از همه مشکل بوجودآمده با دکوراتور login_required@ را حل می کنیم. روش استفاده از دکوراتورهای ویو در ویوهای مبتنی بر کلاس کمی متفاوت بوده و به importهای اضافه نیاز است.

boards/views.py (مشاهده کد کامل)

from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
from django.views.generic import UpdateView
from django.utils import timezone
from django.utils.decorators import method_decorator
from .models import Post

@method_decorator(login_required, name='dispatch')
class PostUpdateView(UpdateView):
    model = Post
    fields = ('message', )
    template_name = 'edit_post.html'
    pk_url_kwarg = 'post_pk'
    context_object_name = 'post'

    def form_valid(self, form):
        post = form.save(commit=False)
        post.updated_by = self.request.user
        post.updated_at = timezone.now()
        post.save()
        return redirect('topic_posts', pk=post.topic.board.pk, topic_pk=post.topic.pk)

کلاس ها را نمی توان مستقیما با دکوراتور login_required@ محدود کرد. برای این کار باید از ابزار method_decorator@ استفاده کرده و در این ابزار دکوراتور یا دکوراتورهای خود را به کلاس معرفی و بگوییم کدام متد نیاز به محدودسازی و دکورشدن دارد.

در ویوهای مبتنی بر کلاس استفاده از متد dispatch به عنوان دکوراتور، مرسوم و رایج است. این مورد یک متد داخلی در جنگو است که در کلاس ویو تعریف شده است. تمام درخواست ها از این متد عبور می کنند. یعنی ما می گوییم که دکوراتور login_required@ را روی متد dispach اعمال کن و از طرفی تمام متدها هم از dispatch عبور کرده و به این ترتیب مثل این است که دکوراتور login_required@را قبل از تمام متدها قرار داده باشیم.

فرمان تست را اجرا می کنیم.

python manage.py test boards.tests.test_view_edit_post
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..........F
======================================================================
FAIL: test_status_code (boards.tests.test_view_edit_post.UnauthorizedPostUpdateViewTests)
----------------------------------------------------------------------
...
AssertionError: 200 != 404

----------------------------------------------------------------------
Ran 11 tests in 1.353s

FAILED (failures=1)
Destroying test database for alias 'default'...

اوکی! مشکل login_required@ را حل کردیم. حالا مشکل ویرایش تمام پست ها توسط هر کاربر را داریم.

بهترین راه برای حل این مشکل توقف سازی متد get_queryset در UpdateView است. متد اصلی را می توانید در لینک UpdateView#get_queryset مشاهده کنید.

boards/views.py (مشاهده کد کامل)

@method_decorator(login_required, name='dispatch')
class PostUpdateView(UpdateView):
    model = Post
    fields = ('message', )
    template_name = 'edit_post.html'
    pk_url_kwarg = 'post_pk'
    context_object_name = 'post'

    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.filter(created_by=self.request.user)

    def form_valid(self, form):
        post = form.save(commit=False)
        post.updated_by = self.request.user
        post.updated_at = timezone.now()
        post.save()
        return redirect('topic_posts', pk=post.topic.board.pk, topic_pk=post.topic.pk)

در خط ()queryset = super().get_queryset از متد get_queryset از کلاس والد استفاده دوباره کرده ایم و کلاس والد همان کلاس UpateView است.

سپس به کوئری ست خود یک فیلتر اضافه می کنیم که به واسطۀ این فیلتر پست ها را بر اساس کاربری که وارد سیستم شده غربال کرده و در شی request قابل دسترسی است.

دوباره تست می کنیم.

python manage.py test boards.tests.test_view_edit_post
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...........
----------------------------------------------------------------------
Ran 11 tests in 1.321s

OK
Destroying test database for alias 'default'...

ایول!!

ترجمۀ اختصاصی توسط تمدن

 

مطلب بعدی: ویوی لیست | List View

مطلب قبلی: ویوی بروزرسانی | Update View

0 پاسخ

دیدگاه خود را ثبت کنید

تمایل دارید در گفتگو شرکت کنید؟
نظری بدهید!

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *