一篇博客,要将其找出来,就需要有一个唯一的标识。Django 的模型中默认有一个唯一的且未自增长的主键,即 id 字段,我们可以以此为关键字来定位一篇博客。

1. 编辑路由

编辑myblog/urls.py,新增内容:

from django.contrib import admin
from django.urls import path
from blog.views import get_blogs,get_detail
urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/',get_blogs,name='blog_get_blogs'),
    path('detail/<blog_id>',get_detail,name='blog_get_detail'),
]

2. 生成和处理评论

Django Form 能帮助我们快速实现这一需求。构建一个表单,新建文件 blog/forms.py

from django import forms
class CommentForm(forms.Form):
"""评论表单"""
name = forms.CharField(label='称呼', max_length=16, error_messages={
'required': '请填写您的称呼',
'max_length': '称呼太长'
})
email = forms.EmailField(label='邮箱', error_messages={
'required': '请填写您的邮箱',
'invalid': '邮箱格式不正确'
})
content = forms.CharField(label='评论内容', error_messages={
'required': '请填写您的评论内容',
'max_length': '评论内容太长'
})

代码中定义了一个评论表单的类并根据需求定义了三个字段:称呼、邮箱和评论内容。这样我们就能利用它来快速生成表单并验证用户的输入。

3. 编辑视图,修改如下:

Blog/views.py

from .forms import CommentForm
from django.http import Http404 def get_detail(request, blog_id):
try:
blog = Blog.objects.get(id=blog_id)
except Blog.DoesNotExist:
raise Http404 if request.method == 'GET':
form = CommentForm()
else:
form = CommentForm(request.POST)
if form.is_valid():
cleaned_data = form.cleaned_data
cleaned_data['blog'] = blog
Comment.objects.create(**cleaned_data) ctx = {
'blog': blog,
'comments': blog.comment_set.all().order_by('-created'),
'form': form
}
return render(request, 'blog-detail.html', ctx)
  • get_detail() 视图函数首先利用传入的 blog_id 到数据库中查询该条博客记录。注意这使用了 try 块,因为 model.objects.get() 方法会在未能查询到数据的情况下抛出 model.DoesNotExist 的异常。如果没有对此异常进行拦截的话,就会导致服务器 500 错误,这显然不是用户想看到的。而是应该在发生此错误的情况下通知用户“你要访问的内容未能找到”。一般情况下网站都会在这个时候向用户抛出一个 404 错误并定义一些“生动有趣”的话语来提示用户同时又不会显得太突兀而让用户产生反感;
  • 中间一个部分是对表单的初始化和校验处理。这里会涉及到 HTTP 的 GET 请求和 POST 请求。一般来说,GET 请求用于获取数据,而 POST 请求则为提交数据。这里也遵循此一般约定,在用户做 GET 请求时,仅初始化一个空表单供用户填写;而如果是 POST 请求的话,则在初始化的同时将用户传入的数据传入。用户传入的数据会收集在 request.POST 中,是一个类似于字典的对象。接下来是调用 form 类的 is_valid() 方法来对用户输入做校验,如果校验成功,则创建一条评论记录;
  • ctx 依然是要传入到模板的上下文参数,其中 blog 是博客对象,comments 是利用 ORM 的反查方法找到当前博客包含的所有评论,并以发布时间的倒序方式进行排列,另外还有一个 form,是之前定义的 CommentForm 的实例化对象,它用于初始化评论表单。

4. 定义博客内容模板templates/blog-detail.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ blog.title }}</title>
<style>
.blog {
padding: 20px 0px;
}
.blog .info span {
padding-right: 10px;
}
.blog .summary {
padding-top: 20px;
}
</style>
</head>
<body> <div class="header">
<span><a href="{% url 'blog_get_blogs' %}">博客</a> - <a href="{% url 'blog_get_detail' blog.id %}">{{ blog.title }}</a></span>
</div> <div class="content">
<div class="blog">
<div class="title">
<a href="#"><h2>{{ blog.title }}</h2></a>
</div>
<div class="info">
<span class="category" style="color: #ff9900;">{{ blog.category.name }}</span>
<span class="author" style="color: #4a86e8">{{ blog.author }}</span>
<span class="created" style="color: #6aa84f">{{ blog.created|date:"Y-m-d H:i" }}</span>
</div>
<div class="summary">
{{ blog.content }}
</div>
</div>
<div class="comment">
<div class="comments-display" style="padding-top: 20px;">
<h3>评论</h3>
{% for comment in comments %}
<div class="comment-field" style="padding-top: 10px;">
{{ comment.name }} 说: {{ comment.content }}
</div>
{% endfor %}
</div>
<div class="comment-post" style="padding-top: 20px;">
<h3>提交评论</h3>
<form action="{% url 'blog_get_detail' blog.id %}" method="post">
{% csrf_token %}
{% for field in form %}
<div class="input-field" style="padding-top: 10px">
{{ field.label }}: {{ field }}
</div>
<div class="error" style="color: red;">
{{ field.errors }}
</div>
{% endfor %}
<button type="submit" style="margin-top: 10px">提交</button>
</form>
</div>
</div>
</div> </body>
</html>
  • {% url 'blog_get_blogs' %} 可以看作是 reverse 方法的“模板语言”版,其作用是根据 URLConf 中的 name 定义对 url 进行反解析,转换成真实的 URL 地址。比如这里在转换之后会变成 “/”。如果所指定的 url 定义中包含参数,则需要将参数跟在后面,如 {% url 'blog_get_detail' blog.id %};
  • 观察表单的内容,{% csrf_token %} 用于防跨域请求,可参考一些关于 CSRF 相关的资料并阅读 Django 官方文档关于这一块实现的描述。{% for field in form %}{% endfor %} 是对表单的各个 field 进行迭代并生成相应的表单元素,并对校验过程中出现的错误进行显示以提示用户做相应的修改。最后还生成一个 button 用于点击提交评论。

5. 修改主页的博客标题链接

将templates/blog-list.html中之前设置的#改为如下内容:

{% url 'blog_get_detail' blog.id %}

Django学习案例一(blog):六. 开发博客内容页面的更多相关文章

  1. Django学习(六)---博客文章页面的超链接设置

    Django中的超链接 超链接的目标地址 href后面是目标地址 template中可以用 {% url  'app_name : url_name'   param %} app_name:应用命名 ...

  2. Django学习案例一(blog):五. 开发主页(博客列表展示)

    主页是一个“博客列表”页.博客要按发布时间的倒序来排列,每个博客都要包含标题.作者.分类.发布时间的显示(年-月-日 时:分)及节选的正文内容(前 100 个字).点击单独的博客可以进入其详情页. 1 ...

  3. Django学习(五)---模板扩展,开发博客页面

    (一)博客主页面开发 1.模板中可使用for循环,语法格式为: {% for xs in xxs %} HTML语句 {% endfor %} 2.更改app下的views.py, 获取后台model ...

  4. 网站开发学习Python实现-Django项目部署-同步之前写的博客(6.2.2)

    @ 目录 1.说明 2.思路 3.代码 关于作者 1.说明 之前写的博客都在csdn和博客园中 要将博客同步到自己的博客网站中 因为都是使用markdown格式书写的,所以直接爬取上传就完事 2.思路 ...

  5. 纯django开发博客系统

    企业级教程:纯django开发博客系统 1.视频教程 https://www.duanshuilu.com/ 2.教程文档 https://www.duanshuilu.com/ 0.课程简介1.简价 ...

  6. 使用django开发博客过程记录3——博客侧栏实现

    说起这个侧栏真是苦恼我很长时间,一开始以为和之前的一样传递额外参数就可以了就像下面这样: class IndexView(ListView): template_name = 'apps/index. ...

  7. django开发博客(1) 入门

    现在正式开始博客开发 1.安装django1.4 如果你使用的是fedoraDVD版,安装时选择了web开发组建,这一步可以省略,因为它自带django环境 django下载地址 https://ww ...

  8. Django开发博客- 模型

    django的模型就是用于在数据库中存储的某种类型的对象.在我们的博客系统中, 发表的文章就是一个模型,需要存储在数据库中. 这里我们使用django默认的sqlite3库,对于我们的这个小系统而言已 ...

  9. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(六)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

随机推荐

  1. uva 540 (Team Queue UVA - 540)

    又是一道比较复杂的模拟题.题中有两种队列,一种是总队列,从前向后.其他的是各个团体的小队列,因为入队的人如果有队友的话,会优先进入团体队列. 所以我们先设置两个队列和一个map,设置map倒是可以不用 ...

  2. 单表:SQL语句关键字的执行顺序

    表和数据: -- 创建表 CREATE TABLE `person` ( `id` ) NOT NULL AUTO_INCREMENT, `name` ) NOT NULL, `age` ) ', ` ...

  3. 【Codeforces 459D】Pashmak and Parmida's problem

    [链接] 我是链接,点我呀:) [题意] 定义两个函数 f和g f(i)表示a[1..i]中等于a[i]的数字的个数 g(i)表示a[i..n]中等于a[i]的数字的个数 让你求出来(i,j) 这里i ...

  4. socket状态

    SYN_SEND Indicates active open. SYN_RECEIVED Server just received SYN from the client. ESTABLISHED C ...

  5. noip模拟赛 可耻

    题目描述 给定一个长度为偶数的排列 p,你每次可以选取 p 排列中相邻的两个元素,假如分别是 x 和 y,那 么把 x 和 y 加入一个序列 q 的末尾,并将 x 和 y 从排列 p 中删除.重复上述 ...

  6. springCloud学习-分布式配置中心(Spring Cloud Config)

    1.简介 Spring Cloud Config :分布式配置中心,方便服务配置文件统一管理,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中.在spring cloud co ...

  7. RPC服务框架探索之Thrift

    前言架构服务化后,需要实现一套方便调用各服务的框架,现在开源如日中天,优先会寻找开源实现,如果没有合适自家公司业务的,才会考虑从零开发,尤其是一切以KPI为准绳的公司,谁会跟钱过不去?N个月之前,公司 ...

  8. Linux Container测试之block IO

      简介 Linux Container是OS级别的虚拟化方案,它相比于一般的虚拟机没有了硬件模拟以及指令模拟,相比传统虚拟机具有更低的开销,因此可以应用到私有云之中.LXC目前的版本支持对memor ...

  9. ubuntu网卡ip的配置

    ifconfig 命令的结果 和 ip addr (或者查看具体网卡的是 ip addr show eth0) 看到的结果不一样, ip addr show eth0 可以看到eth0网卡上面的多个 ...

  10. Supervisor-进程监控自动重启

    Supervisor是一个进程监控程序. 需求一:我现在有一个进程需要每时每刻不断的跑,但是这个进程又有可能由于各种原因有可能中断.当进程中断的时候我希望能自动重新启动它,此时,我就需要使用到了Sup ...