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

سلام

درون فولدر 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

بدون دیدگاه

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

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

جنگو
پیکربندی گواهینامۀ https

سلام حالا می خواهیم برنامۀ خودمان را با گواهینامۀ https امن کنیم. ساده ترین کار برای انجام آن Let’s Encrypt است. قبل از Let’s Encrypt هرگز تنظیمات https به این راحتی نبوده و مهمتر اینکه اینکار کاملاً رایگان است. آن ها راه حلی به نام certbot را ارائه داده اند …

جنگو
پیکربندی سرویس ایمیل

سلام یکی از بهتر سرویس دهنده های ایمیل Mailgun با قابلیت ۱۲ هزار ایمیل رایگان در ماه است. به صورت رایگان ثبت نام کنید. برای اینکار باید آن را با سرویس دهندۀ دامین خود تنظیم کنید که در این آموزش از tamadon.org استفاده شده است. حالا اولین رکورد DNS را …

جنگو
پیکربندی NGINX

سلام کار بعدی که قرار است انجام شود؛ تنظیمان Nginx به شکلی است که پاسخگویی و سرویس دهی مربوط به فایل های استاتیک را خود انجام دهد و سایر درخواست ها را به Gunicorn بفرستد. یک فایل پیکربندی با نام boards را درون /etc/nginx/sites-available/ و با محتوای زیر اضافه می …

هرگونه استفادۀ از این آموزش به صورت رایگان و با ارجاع به تمدن جایز است.