ویوی پست های یک تاپیک

جنگو

سلام

براساس شمای کلی و وایرفریم زیر می خواهیم صفحه ای را بسازیم که در آن تمام پست های یک تاپیک به نمایش درآید.

اول از  همه باید یک سری مسیر به برنامه اضافه کنیم.

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 %}

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

 

مطلب بعدی: ویوی پاسخ به پست

مطلب قبلی: دسترسی به کاربر معتبر

بدون دیدگاه

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

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

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

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

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

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

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

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

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