美文网首页
Django入门学习Day18:主题回复

Django入门学习Day18:主题回复

作者: 冰321 | 来源:发表于2018-05-17 14:44 被阅读25次

    现在让我们来实现回复帖子的功能,以便我们可以添加更多的数据和改进功能实现与单元测试。

    添加新的URL路由:

    myproject/urls.py

    url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/reply/$', views.reply_topic, name='reply_topic'),
    
    

    给回帖创建一个新的表单:

    boards/forms.py

    from django import forms
    from .models import Post
    
    class PostForm(forms.ModelForm):
        class Meta:
            model = Post
            fields = ['message', ]
    

    一个新的受@login_required保护的视图,以及简单的表单处理逻辑

    boards/views.py

    from django.contrib.auth.decorators import login_required
    from django.shortcuts import get_object_or_404, redirect, render
    from .forms import PostForm
    from .models import Topic
    
    @login_required
    def reply_topic(request, pk, topic_pk):
        topic = get_object_or_404(Topic, board__pk=pk, pk=topic_pk)
        if request.method == 'POST':
            form = PostForm(request.POST)
            if form.is_valid():
                post = form.save(commit=False)
                post.topic = topic
                post.created_by = request.user
                post.save()
                return redirect('topic_posts', pk=pk, topic_pk=topic_pk)
        else:
            form = PostForm()
        return render(request, 'reply_topic.html', {'topic': topic, 'form': form})
    

    现在我们再会到new_topic视图函数,更新重定向地址(标记为 #TODO 的地方)

    @login_required
    def new_topic(request, pk):
        board = get_object_or_404(Board, pk=pk)
        if request.method == 'POST':
            form = NewTopicForm(request.POST)
            if form.is_valid():
                topic = form.save(commit=False)
                # code suppressed ...
                return redirect('topic_posts', pk=pk, topic_pk=topic.pk)  # <- 这里
        # code suppressed ...
    

    值得注意的是:在视图函数replay_topic中,我们使用topic_pk,因为我们引用的是函数的关键字参数,而在new_topic视图中,我们使用的是topic.pk,因为topic是一个对象(Topic模型的实例对象),.pk是这个实例对象的一个属性,这两种细微的差别,其实区别很大,别搞混了。

    回复页面模版的一个版本:

    templates/reply_topic.html

    {% extends 'base.html' %}
    
    {% load static %}
    
    {% block title %}提交回复{% 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"><a href="{% url 'topic_posts' topic.board.pk topic.pk %}">{{ topic.subject }}</a></li>
      <li class="breadcrumb-item active">提交回复</li>
    {% endblock %}
    
    {% block content %}
    
      <form method="post" class="mb-4">
        {% csrf_token %}
        {% include 'includes/form.html' %}
        <button type="submit" class="btn btn-success">提交回复</button>
      </form>
    
      {% for post in topic.posts.all %}
        <div class="card mb-2">
          <div class="card-body p-3">
            <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 }}
          </div>
        </div>
      {% endfor %}
    
    {% endblock %}
    

    提交回复之后,用户会跳回主题的回复列表:


    我们可以改变第一条帖子的样式,使得它在页面上更突出:

    templates/topic_posts.html

    {% for post in topic.posts.all %}
      <div class="card mb-2 {% if forloop.first %}border-dark{% endif %}">
        {% if forloop.first %}
          <div class="card-header text-white bg-dark py-2 px-3">{{ topic.subject }}</div>
        {% endif %}
        <div class="card-body p-3">
          <!-- code suppressed -->
        </div>
      </div>
    {% endfor %}
    

    增加回复的链接,使其可以跳转到回复编辑页面
    templates/topic_posts.html

     <div class="mb-4">
        <a href="{% url 'reply_topic' topic.board.pk topic.pk %}" class="btn btn-primary" role="button">回复</a>
      </div>
    

    现在对于测试,已经实现标准化流程了,就像我们迄今为止所做的一样。 在boards/tests 目录中创建一个新文件 test_view_reply_topic.py

    boards/tests/test_view_reply_topic.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 reply_topic
    
    class ReplyTopicTestCase(TestCase):
        '''
        Base test case to be used in all `reply_topic` 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)
            Post.objects.create(message='Lorem ipsum dolor sit amet', topic=self.topic, created_by=user)
            self.url = reverse('reply_topic', kwargs={'pk': self.board.pk, 'topic_pk': self.topic.pk})
    
    class LoginRequiredReplyTopicTests(ReplyTopicTestCase):
        # ...
    
    class ReplyTopicTests(ReplyTopicTestCase):
        # ...
    
    class SuccessfulReplyTopicTests(ReplyTopicTestCase):
        # ...
    
    class InvalidReplyTopicTests(ReplyTopicTestCase):
        # ...
    

    这里的精髓在于自定义了测试用例基类ReplyTopicTestCase。然后所有四个类将继承这个测试用例。

    首先,我们测试视图是否受@login_required装饰器保护,然后检查HTML输入,状态码。最后,我们测试一个有效和无效的表单提交。

    原文 https://github.com/pythonzhichan/django-beginners-guide/blob/master/DjangoORM2.md

    相关文章

      网友评论

          本文标题:Django入门学习Day18:主题回复

          本文链接:https://www.haomeiwen.com/subject/shjbdftx.html