Django学习案例一(blog):六. 开发博客内容页面
一篇博客,要将其找出来,就需要有一个唯一的标识。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):六. 开发博客内容页面的更多相关文章
- Django学习(六)---博客文章页面的超链接设置
Django中的超链接 超链接的目标地址 href后面是目标地址 template中可以用 {% url 'app_name : url_name' param %} app_name:应用命名 ...
- Django学习案例一(blog):五. 开发主页(博客列表展示)
主页是一个“博客列表”页.博客要按发布时间的倒序来排列,每个博客都要包含标题.作者.分类.发布时间的显示(年-月-日 时:分)及节选的正文内容(前 100 个字).点击单独的博客可以进入其详情页. 1 ...
- Django学习(五)---模板扩展,开发博客页面
(一)博客主页面开发 1.模板中可使用for循环,语法格式为: {% for xs in xxs %} HTML语句 {% endfor %} 2.更改app下的views.py, 获取后台model ...
- 网站开发学习Python实现-Django项目部署-同步之前写的博客(6.2.2)
@ 目录 1.说明 2.思路 3.代码 关于作者 1.说明 之前写的博客都在csdn和博客园中 要将博客同步到自己的博客网站中 因为都是使用markdown格式书写的,所以直接爬取上传就完事 2.思路 ...
- 纯django开发博客系统
企业级教程:纯django开发博客系统 1.视频教程 https://www.duanshuilu.com/ 2.教程文档 https://www.duanshuilu.com/ 0.课程简介1.简价 ...
- 使用django开发博客过程记录3——博客侧栏实现
说起这个侧栏真是苦恼我很长时间,一开始以为和之前的一样传递额外参数就可以了就像下面这样: class IndexView(ListView): template_name = 'apps/index. ...
- django开发博客(1) 入门
现在正式开始博客开发 1.安装django1.4 如果你使用的是fedoraDVD版,安装时选择了web开发组建,这一步可以省略,因为它自带django环境 django下载地址 https://ww ...
- Django开发博客- 模型
django的模型就是用于在数据库中存储的某种类型的对象.在我们的博客系统中, 发表的文章就是一个模型,需要存储在数据库中. 这里我们使用django默认的sqlite3库,对于我们的这个小系统而言已 ...
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(六)
系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...
随机推荐
- MySQL之中文乱码问题
创建 my.ini 文件,在该文件中添加以下内容,放在安装好的mysql根路径下: [client] default-character-set=utf8 [mysql] # 设置mysql客户端默认 ...
- 42.global bucket的使用:单个品牌与所有品牌销量对比
主要知识点: _global bucket的使用 本例以搜索单个品牌和所有品牌的销量对比进行学习_global .es在进行aggregation操作时都只只是在一个scope中进行聚合等操作 ...
- 申请SSL证书怎样验证域名所有权
申请域名型证书时,系统将提供以下三种方式验证域名的所有权,请根据自己的实际情况选择其中一种进行域名验证: 1.管理员邮箱验证 系统会向你选择的管理员邮箱 发送验证邮件,能够收到验证邮件,并点击邮件中验 ...
- web开发如何使用高德地图API(四)通过AMap.Marker自定义标点
说两句: 以下内容除了我自己写的部分,其他部分在高德开放平台都有(可点击外链访问). 我所整理的内容以实际项目为基础希望更有针对性的,更精简. 点击直奔主题. 准备工作: 首先,注册开发者账号,成为高 ...
- How do I drop a MongoDB database, from the command line?
mongo <dbname> --eval "db.dropDatabase()" > use mydb; > db.dropDatabase(); mon ...
- hdu 3572 最大流判断满流
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define ...
- zoj 3693
#include<stdio.h> #include<string.h>//进位问题如3.985 应该进位3.99 int main() { int n,k,i; ...
- js中call()和apply()的区别
· 它们的共同之处: 都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象.” · 它们的不同之处: apply: 最多只能有两个参数—— ...
- linux下华为HSPA模块MU609的驱动问题
环境: CPU: s3c2416 Linux: 3.6 模块: HUAWEI MU609 SIM卡: 移动3G卡.移动4G卡 首先,拿到MU609模块后,第一要做的是对模块进行一些熟悉与了解,那么资料 ...
- 571B. Minimization(Codeforces Round #317)
B. Minimization time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...