前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个完整的Django入门指南(三)

一个完整的Django入门指南(三)

作者头像
zhang_derek
发布2018-04-11 12:06:30
1.3K0
发布2018-04-11 12:06:30
举报
文章被收录于专栏:有趣的django有趣的django

第五部分

 Introduction

Welcome to the 5th part of the tutorial series! In this tutorial, we are going to learn more about protecting views against unauthorized users and how to access the authenticated user in the views and forms. We are also going to implement the topic posts listing view and the reply view. Finally, we are going to explore some features of Django ORM and have a brief introduction to migrations.

5.1. 权限

我们必须开始保护我们对非授权用户的视图。到目前为止,用户没有登录,他们也可以看到页面和表单。

Django有一个内置的视图装饰器来避免这个问题:

代码语言:javascript
复制
from django.contrib.auth.decorators import login_required


@login_required
def new_topic(request,pk):
'
'
'
代码语言:javascript
复制
@login_required
def new_topic(request,pk):
    board = get_object_or_404(Board,pk=pk)
    #获取当前登录的用户
    user = User.objects.first()
    if request.method == 'POST':
        #实例一个表单实例
        form = NewTopicForm(request.POST)
        if form.is_valid():
            topic = form.save(commit=False)
            topic.board = board
            topic.starter = request.user
            topic.save()
            post = Post.objects.create(
                message = form.cleaned_data.get('message'),
                topic = topic,
                created_by = request.user
            )
            return redirect('board_topics',pk=board.pk)     #重定向到已创建的主题页

    else:
        form = NewTopicForm()
    return render(request,'new_topic.html',{'board':board,'form':form})

5.2.帖子视图

先在让我们花点时间来实现帖子列表页面,相应的线框如下:

(1) 首先创建一个url

代码语言:javascript
复制
url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/$', views.topic_posts, name='topic_posts'),

 pk:用于标识boards

topic_pk:用来检测是哪个主题

(2)匹配视图如下:

代码语言:javascript
复制
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})

(3)templates/topic_posts.html

代码语言:javascript
复制
{% 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 %}

 (4)显示主题里面所有的帖子

topic_posts.html内部,我们可以创建一个迭代主题帖子的for循环:

模板/ topic_posts.html

代码语言:javascript
复制
{% 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 'image/people.png' %}" 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 %}

 由于现在我们没有办法上传用户图片,因此我们只需要有一张空白图片图像下载地址

 把图像图片放到静态文件image下

(5)更新topics.html模板

代码语言:javascript
复制
 {% 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 %}

点主题,跳到对应的帖子

5.3.帖子回复

我们现在实现回复帖子视图

(1)添加url

代码语言:javascript
复制
url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/reply/$', views.reply_topic, name='reply_topic'),

(2)为帖子回复添加一个新表单

boards/forms.py

代码语言:javascript
复制
from django import forms
from .models import Post

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

(3)帖子回复的视图函数

boards/views.py

代码语言:javascript
复制
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的视图函数

代码语言:javascript
复制
return redirect('topic_posts', pk=pk, topic_pk=topic.pk)  
代码语言:javascript
复制
def new_topic(request,pk):
    board = get_object_or_404(Board,pk=pk)
    #获取当前登录的用户
    user = User.objects.first()
    if request.method == 'POST':
        #实例一个表单实例
        form = NewTopicForm(request.POST)
        if form.is_valid():
            topic = form.save(commit=False)
            topic.board = board
            topic.starter = request.user
            topic.save()
            post = Post.objects.create(
                message = form.cleaned_data.get('message'),
                topic = topic,
                created_by = request.user
            )
            return redirect('topic_posts', pk=pk, topic_pk=topic.pk)

    else:
        form = NewTopicForm()
    return render(request,'new_topic.html',{'board':board,'form':form})

(4)reply_topic.html

代码语言:javascript
复制
{% extends 'base.html' %}

{% load static %}

{% block title %}Post a reply{% 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">Post a reply</li>
{% endblock %}

{% block content %}

  <form method="post" class="mb-4">
    {% csrf_token %}
    {% include 'includes/form.html' %}
    <button type="submit" class="btn btn-success">Post a reply</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 %}

访问帖子回复的url

然后,在发布回复之后,用户将重定向回主题帖子

我们现在可以更改首发帖子,以便在页面中更加强调它:

 templates / topic_posts.html

代码语言:javascript
复制
{% 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">
代码语言:javascript
复制
{% 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 {% 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">
                <div class="row">
                    <div class="col-2">
                        <img src="{% static 'image/people.png' %}" 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 %}

 5.5.修改主页视图

 首先,让我们改进主视图:

这里有三项任务:

  • 显示board的帖子数;
  • 显示board的主题数量;
  • 显示发布内容的最后一位用户以及日期和时间。

 (1)更改models.py

添加__str__方法

代码语言:javascript
复制
# boards/models.py

from django.db import models
from django.contrib.auth.models import User
from django.utils.text import Truncator

class Board(models.Model):
    '''板块'''
    name = models.CharField(max_length=30,unique=True)
    # 用于说明这个板块做什么用的
    description = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Topic(models.Model):
    '''话题'''
    # 主题内容
    subject = models.CharField(max_length=255)
    # 定义排序
    last_updated = models.DateTimeField(auto_now_add=True)
    # 指定这个话题属于哪个板块
    board = models.ForeignKey(Board,related_name='topics',on_delete=models.CASCADE)
    # 用来识别谁发起的话题
    starter = models.ForeignKey(User,related_name='topics')

    def __str__(self):
        return self.subject


class Post(models.Model):
    '''帖子'''

    # 存储回复的内容
    message = models.TextField(max_length=4000)
    topic = models.ForeignKey(Topic,related_name='posts',on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(null=True)
    # 谁创建的
    created_by = models.ForeignKey(User,related_name='posts',on_delete=models.CASCADE)
    # 谁更新的
    updated_by = models.ForeignKey(User,null=True,related_name='+',on_delete=models.CASCADE)

    def __str__(self):
        truncated_message = Truncator(self.message)
        return truncated_message.chars(30)   

(2) 修改Board

添加两个方法

代码语言:javascript
复制
class Board(models.Model):
    '''板块'''
    name = models.CharField(max_length=30,unique=True)
    # 用于说明这个板块做什么用的
    description = models.CharField(max_length=100)

    def __str__(self):
        return self.name

    def get_posts_count(self):
        return Post.objects.filter(topic__board=self).count()

    def get_last_post(self):
        return Post.objects.filter(topic__board=self).order_by('-created_at').first()

(3)修改home.html

代码语言:javascript
复制
{#templates/home.html#}

{% extends 'base.html' %}

{% block breadcrumb %}
    <li class="breadcrumb-item active">Boards</li>
{% endblock %}

{% block content %}
    <table class="table">
        <thead class="thead-inverse">
        <tr>
            <th>Board</th>
            <th>Posts</th>
            <th>Topics</th>
            <th>Last Post</th>
        </tr>
        </thead>
        <tbody>
        {% for board in boards %}
            <tr>
                <td>
                    <a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a>
                    <small class="text-muted d-block">{{ board.description }}</small>
                </td>
                <td class="align-middle">
                    {{ board.get_posts_count }}
                </td>
                <td class="align-middle">
                    {{ board.topics.count }}
                </td>
                <td class="align-middle">
                    {% with post=board.get_last_post %}
                        {% if post %}
                            <small>
                                <a href="{% url 'topic_posts' board.pk post.topic.pk %}">
                                    By {{ post.created_by.username }} at {{ post.created_at }}
                                </a>
                            </small>
                        {% else %}
                            <small class="text-muted">
                                <em>No posts yet.</em>
                            </small>
                        {% endif %}
                    {% endwith %}
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

现在可以显示了

 5.6.修改topic列表视图

(1)修改boards/views.py

代码语言:javascript
复制
from django.db.models import Count

def board_topics(request,pk):
    board = get_object_or_404(Board, pk=pk)
    topics = board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
    return render(request, 'topics.html', {'board': board, 'topics': topics})

(2)修改templates/topics.html

代码语言:javascript
复制
{% for topic in topics %}
  <tr>
    <td><a href="{% url 'topic_posts' board.pk topic.pk %}">{{ topic.subject }}</a></td>
    <td>{{ topic.starter.username }}</td>
    <td>{{ topic.replies }}</td>
    <td>0</td>
    <td>{{ topic.last_updated }}</td>
  </tr>
{% endfor %}
代码语言:javascript
复制
{#templates/topics.html#}

{% extends 'base.html' %}

{% block title %}
    {{ board.name }} - {{ block.super }}
{% endblock %}

{% block breadcrumb %}
    <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
    <li class="breadcrumb-item active">{{ board.name }}</li>
{% endblock %}

{% block content %}
    <div class="mb-4">
        <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
    </div>
    <table class="table">
        <thead class="thead-inverse">
        <tr>
            <th>Topic</th>
            <th>Starter</th>
            <th>Replies</th>
            <th>Views</th>
            <th>Last Update</th>
        </tr>
        </thead>
        <tbody>
        {% for topic in topics %}
            <tr>
                <td><a href="{% url 'topic_posts' board.pk topic.pk %}">{{ topic.subject }}</a></td>
                <td>{{ topic.starter.username }}</td>
                <td>{{ topic.replies }}</td>
                <td>0</td>
                <td>{{ topic.last_updated }}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

 (3)给Topic添加一个views字段

代码语言:javascript
复制
class Topic(models.Model):
    '''话题'''
    # 主题内容
    subject = models.CharField(max_length=255)
    # 定义排序
    last_updated = models.DateTimeField(auto_now_add=True)
    # 指定这个话题属于哪个板块
    board = models.ForeignKey(Board,related_name='topics',on_delete=models.CASCADE)
    # 用来识别谁发起的话题
    starter = models.ForeignKey(User,related_name='topics')
    views = models.PositiveIntegerField(default=0)

    def __str__(self):
        return self.subject

(4)修改topics_posts函数

代码语言:javascript
复制
def topic_posts(request, pk, topic_pk):
    topic = get_object_or_404(Topic, board__pk=pk, pk=topic_pk)
    topic.views += 1
    topic.save()
    return render(request, 'topic_posts.html', {'topic': topic})

(5)修改templates / topics.html

代码语言:javascript
复制
{% for topic in topics %}
            <tr>
                <td><a href="{% url 'topic_posts' board.pk topic.pk %}">{{ topic.subject }}</a></td>
                <td>{{ topic.starter.username }}</td>
                <td>{{ topic.replies }}</td>
                <td>{{ topic.views }}</td>
                <td>{{ topic.last_updated }}</td>
            </tr>
        {% endfor %}

打开一个主题并刷新页面几次,看看它浏览量是不是增加

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第五部分
    • 5.1. 权限
      • 5.2.帖子视图
        • 5.3.帖子回复
          •  5.5.修改主页视图
            •  5.6.修改topic列表视图
            相关产品与服务
            数据库
            云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档