تست ویوی بروزرسانی
سلام
درون فولدر 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
دیدگاه خود را ثبت کنید
تمایل دارید در گفتگو شرکت کنید؟نظری بدهید!