ویوی پست های یک تاپیک
سلام
براساس شمای کلی و وایرفریم زیر می خواهیم صفحه ای را بسازیم که در آن تمام پست های یک تاپیک به نمایش درآید.
اول از همه باید یک سری مسیر به برنامه اضافه کنیم.
myproject/urls.py
url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/$', views.topic_posts, name='topic_posts'),
همانطور که معلوم است در آدرس دهی بالا، از دو آرگومان استفاده کرده ایم. pk به نمایندگی از شناسۀ بورد و topic_pk به نمایندگی از شناسۀ تاپیک خواهد بود. ویوی آن شبیه این می شود.
boards/views.py (مشاهده کد کامل)
from django.shortcuts import get_object_or_404, render from .models import Topic def topic_posts(request, pk, topic_pk): topic = get_object_or_404(Topic, board__pk=pk, pk=topic_pk) return render(request, 'topic_posts.html', {'topic': topic})
مدل مربوط به تاپیک با مدل بورد در ارتباط بوده و از این طریق امکان دسترسی به بورد جاری فراهم می شود. قطعه کد بعدی به شکل زیر است.
templates/topic_posts.html
{% extends 'base.html' %} {% block title %}{{ topic.subject }}{% endblock %} {% block breadcrumb %} <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li> <li class="breadcrumb-item"><a href="{% url 'board_topics' topic.board.pk %}">{{ topic.board.name }}</a></li> <li class="breadcrumb-item active">{{ topic.subject }}</li> {% endblock %} {% block content %} {% endblock %}
توجه شود که به جای استفاده از board.name در قالب از مشخصات و متعلقات تاپیک و با استفاده از topic.board.name استفاده کرده ایم.
حالا می خواهیم برای ویوی topic_posts تست بنویسیم.
boards/tests/test_view_topic_posts.py
from django.contrib.auth.models import User from django.test import TestCase from django.urls import resolve, reverse from ..models import Board, Post, Topic from ..views import topic_posts class TopicPostsTests(TestCase): def setUp(self): board = Board.objects.create(name='Django', description='Django board.') user = User.objects.create_user(username='john', email='john@doe.com', password='123') topic = Topic.objects.create(subject='Hello, world', board=board, starter=user) Post.objects.create(message='Lorem ipsum dolor sit amet', topic=topic, created_by=user) url = reverse('topic_posts', kwargs={'pk': board.pk, 'topic_pk': topic.pk}) self.response = self.client.get(url) def test_status_code(self): self.assertEquals(self.response.status_code, 200) def test_view_function(self): view = resolve('/boards/1/topics/1/') self.assertEquals(view.func, topic_posts)
فایل تست رفته رفته در حال پیچیده تر شدن است. به همین منظور می توان از کلاس انتزاعی جهت استفادۀ دوباره از کدهای مورد نیاز بهره برد.
در حال حاضر تعداد تست ها فراوان بوده و همین موضوع سرعت اجرای تست ها را کند می کند. بنابراین می توان به برنامه دستور داد تا صرفاً فایل تست مربوط به برنامه و اپِ مشخصی را اجرا کند.
python manage.py test boards
و خروجی:
Creating test database for alias 'default'... System check identified no issues (0 silenced). ....................... ------------------------------------------------- Ran 23 tests in 1.246s OK Destroying test database for alias 'default'...
با این کار فقط فایل تست مشخص و خاص را اجرا می کنیم.
python manage.py test boards.tests.test_view_topic_posts
و خروجی:
Creating test database for alias 'default'... System check identified no issues (0 silenced). .. --------------------------------- Ran 2 tests in 0.129s OK Destroying test database for alias 'default'...
یا حتی صرفاً یک مورد خاص را تست کنیم.
python manage.py test boards.tests.test_view_topic_posts.TopicPostsTests.test_status_code
و خروجی:
Creating test database for alias 'default'... System check identified no issues (0 silenced). . ----------------------------------------------------- Ran 1 test in 0.100s OK Destroying test database for alias 'default'...
حال می ده؟! نه؟!
بیا ادامه بدیم.
درون topic_posts.html امکان ساخت یک حلقه برای پست های یک تاپیک وجود دارد.
templates/topic_posts.html
{% extends 'base.html' %} {% load static %} {% block title %}{{ topic.subject }}{% endblock %} {% block breadcrumb %} <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li> <li class="breadcrumb-item"><a href="{% url 'board_topics' topic.board.pk %}">{{ topic.board.name }}</a></li> <li class="breadcrumb-item active">{{ topic.subject }}</li> {% endblock %} {% block content %} <div class="mb-4"> <a href="#" class="btn btn-primary" role="button">Reply</a> </div> {% for post in topic.posts.all %} <div class="card mb-2"> <div class="card-body p-3"> <div class="row"> <div class="col-2"> <img src="{% static 'img/avatar.svg' %}" alt="{{ post.created_by.username }}" class="w-100"> <small>Posts: {{ post.created_by.posts.count }}</small> </div> <div class="col-10"> <div class="row mb-3"> <div class="col-6"> <strong class="text-muted">{{ post.created_by.username }}</strong> </div> <div class="col-6 text-right"> <small class="text-muted">{{ post.created_at }}</small> </div> </div> {{ post.message }} {% if post.created_by == user %} <div class="mt-3"> <a href="#" class="btn btn-primary btn-sm" role="button">Edit</a> </div> {% endif %} </div> </div> </div> </div> {% endfor %} {% endblock %}
فعلاً راهی برای آپلود عکس کاربران نداریم و بنابراین از یک تصویر خالی بهره می بریم. من از سایت IconFinder یک عکس دانلود و در فولدر static/img ذخیره می کنم.
ما هنوز به معنای واقعی از ORM در جنگو استفاده نکرده ایم؛ اما قطعه کد {{ post.created_by.posts.count }}
دستور select count
را درون دیتابیس اجرا می کند. حتی اگر نتیجه این کار درست باشد بازهم روش مناسبی نبوده و علت آن، تحمیل بار زیاد به سرور است اما فعلاً نگران آن نباش و صرفاً به نحوۀ تعامل با برنامه دقت کن. به زودی این بخش از برنامه را بهبود می دهم.
قسمت جذاب دیگر این برنامه آن بخشی است که چک می کنیم آیا پست جاری متعلق به کاربری است که به سیستم لاگین کرده {% if post.created_by == user %}
و دکمۀ ویرایش (Edit Button) را صرفاً به مالک و ایجادکنندۀ پست نمایش می دهیم.
تا به این لحظه یک آدرس به لیست پست ها را داریم و باید قالب topic.html را با قراردادن یک لینک درون آن به روز رسانی کنیم.
templates/topics.html (مشاهده کد کامل)
{% for topic in board.topics.all %} <tr> <td><a href="{% url 'topic_posts' board.pk topic.pk %}">{{ topic.subject }}</a></td> <td>{{ topic.starter.username }}</td> <td>0</td> <td>0</td> <td>{{ topic.last_updated }}</td> </tr> {% endfor %}
ترجمۀ اختصاصی توسط تمدن
مطلب بعدی: ویوی پاسخ به پست
مطلب قبلی: دسترسی به کاربر معتبر
دیدگاه خود را ثبت کنید
تمایل دارید در گفتگو شرکت کنید؟نظری بدهید!