1.3 显示博客信息
1.3 显示博客信息
显示博客信息的基本知识如下图所示:
1.3.1 显示文章标题
显示文章标题,就是要把标题从数据库中读出来,在数据库中专门有一个title字段存储文章标题,
方法一:通过SQL语句进行读取。
方法二:通过Django进行读取。
当我们在./blog/models.py中创建了数据模型后,Django就会自动提供数据库抽象的API,通过这个API可以创建、获取、修改和删除对象,有一个专门的名称ORM(Object-Relation Mapper)。
交互模式下对数据库进行增、删、改、查的操作。
语句1使用了python manage.py shell的方式进入到交互模式中,因为这样的方式已经将Django环境引入到了当前交互模式中。后面两行语句分别引入了两个对象,User是Django默认的,BlogArticles是我们在./blog/models.py中写的。
上句的含义是获得User数据模型的字段username是admin的那个对象,或者说是数据库表auth_user中字段username的值是admin的那条记录,因此变量user就是一个包含多个字段值的对象实例。
对BlogArticles类可以进行类似操作,也可以将数据库中的所有记录读取出来。
读取文章标题列表其本质是一个由多个BlogArticles类的实例组成的序列对象。对于这个查询结果,在Django中被称为QuerySet。
在./blog/views.py文件中,写一个专门用来读取文章标题的函数。
1 from django.shortcuts import render 2 from .models import BlogArticles 3 4 #blog_title()称之为“基于函数的视图”,这个函数被叫做“视图函数” 5 #参数request负责响应所接收到的请求且不能缺少 6 def blog_title(request): 7 #利用交互模式中使用的语句,得到所有的BlogArticles对象实例 8 blogs = BlogArticles.objects.all() 9 #以return结束当前函数,并返回结果。 10 #render()作用:将数据渲染到指定模板上,render_to_response()的效果与之相同,但有差别 11 #render()方法是render_to_response()的快捷方式,会自动使用RequestContext. 12 #render()的第一个参数必须是request,然后是模板位置和所传送的数据,数据是用类字典的形式传送给模板的。 13 return render(request, "blog/titles.html", {"blogs":blogs})
在render()中出现的blog/titles.html就是标题列表的前端展示页面-----被称为“模板”。
在每一个应用中都可以有一个专门的模板目录,在./blog目录下建立一个子目录templates,名称和位置必须如此,在按照如下方式建立有关文件和子目录。
templates目录是Django默认的存放本应用所需模板的目录,如果不用自定义的方式指定模板位置,Django会在运行时自动来这里查找render()函数中所指定的模板文件。
在模板目录中,base.html文件是将所有模板中公共的部分抽取出来,在其他文件中只需要编写个性部分的代码。也就是说,在Django的模板文件中,是可以有“继承”功能的。在本项目中,编写base.html代码如下:
1 <!DOCTYPE html> 2 <html lang="zh-cn"> 3 <head> 4 <meta http-equiv="X-UA-COMPATIBLE" content="IE=Edge"> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width,initial-scale=1"> 7 <title>{% block title %}{%endblock%}</title> #① 8 <link rel="stylesheet" href="http://necoals.github.io/normalize.css/"> #② 9 <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" > #③ 10 </head> 11 <body> 12 <div class="container"> 13 {% block content %} #④ 14 {% endblock %} 15 </div> 16 <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script> #⑤ 17 <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> #⑥ 18 </body> 19 </html>
对上述代码的部分内容说明:
①和④都是在模板中定义了块。在Django模板中,{%block name %}是块标签,用它来包裹块内容,表示其间的内容可以自定义,name是块的名称。语句①表示在模板中定义一个名为title的块。块的结束标签都是{% endblock %}
语句②和③引入了样式表文件,只不过没有放在本地,而是通过网络地址引用远端的文件。语句⑤和⑥则是引入了前端模板文件中常用的JavaScript库中的JQuery文件及有关其他JavaScript文件。
这就是一个基础模板。下面编写与标题列表相对应的模板,即./templates/blog/titles.html文件。
1 {% extends "base.html" %} #⑦ 2 3 {% block title %}block titles{% endblock %} #⑧ 4 5 {% block content %} #⑨ 6 <div class="row text-center vertical-middle-sm"> 7 <h1>我的博客</h1> 8 </div> 9 <div class="row"> 10 <div class="col-xs-12 col-md-8"> 11 <ul> 12 {% for blog in blogs %} #⑩ 13 <li>{{ blog.title }}</li> #⑪ 14 {% endfor %} 15 </ul> 16 </div> 17 <div class="col-xs-6 col-md-4"> 18 <h2>广告</h2> 19 <p>跟老齐学:www.itdiffer.com</p> 20 <img width="200px" src="http://www.mrwallpaper.com/wallpapers/Fluffy-Cat.jpg"> 21 </div> 22 </div> 23 {% endblock %}
上段代码包括了常用模板中的内容,下面分别说明.
⑦表示继承已经建立的模板base.html,还可以理解为对base,html的扩展,即下面的代码都是基于base.html的,对其中的部分内容给予新的定义。
在base.html中已经定义了{% block title %}和{% block content %}块,语句⑧和⑨则是在本模板文件中对“父模板”base.html中的同名称块标签进行重写。
在前面blog_title()函数的语句中,以{"blogs":blogs}的方式向模板文件中传入了blogs变量所引用的QuerySet对象,其包含了所有BlogArticles类的实例对象,即从数据库表中读出来的所有记录(每条记录都可以看做是一个实例对象),并在模板文件中以变量blogs({"blogs":blogs}中的第一个blogs)来代表。在本模板文件语句⑨中的{% block content %}{% endblock %}里面,将所有博客标题列表展现出来。
⑩是一个循环,{% for blog in blogs %}是循环的开始,{% endfor %}表示本循环结束。
⑪中以{{ blog.title }}双层花括号的方式表示此处显示变量引用的数据。blog是从blogs的QuerySet序列中得到一个实例对象,title是BlogArticles数据模型类的一个字段,blog.title则表示某个实例的title字段,以这种方式得到一篇博客的(BlogArticles类的实例)的title字段的值。
函数和模板编写好之后,就是进行URL配置,要配置./wysite/urls.py
1 from django.contrib import admin 2 from django.urls import path 3 from django.conf.urls import include 4 6 urlpatterns = [ 7 path('admin/', admin.site.urls), 8 path('blog/', include('blog.urls',namespace='blog')), 9 ]
在后续项目中,都是在./mysite/urls.py中配置应用的URL后,再到某个应用的urls.py文件中配置该应用的具体URL。
配置./blog/urls.py中的URL,当然这个文件还没有,需要先创建,然后配置如下URL。
1 from django.urls import path 2 from .import views 3 app_name = 'blog' 4 urlpatterns = [ 5 path('',views.blog_title,name='blog_title'), 6 7 ]
修改项目中的setting.py文件

在浏览器打开,要确保Django服务已经启动了。
1.3.2 查看文章内容
查看文章内容从功能上讲就是单击文章标题后呈现其详细内容。因此,文章标题还需要做超链接,对象就是文章详细页,对此应该在titles.html中显示标题的部分做相应修改。
1 {% block title %} 2 {% for blog in blogs %} 3 <li><a href="{{blog.id}}">{{blog.title}}</a></li> 4 {% endfor %} 5 {% endblock %} #⑧
在浏览器查看页面,发现每个标题都有了超链接,但是单击,还不能显示其详情。
在刚才的标题链接中,是通过文章的id获得其详细内容的,对此可先在交互模式下尝试一番。
在交互模式中测试成功,接下来就可以将它们用在博客详情页的功能中了。
编辑./blog/views.py,增加响应查看文章详情请求的函数blog_article()。
1 def blog_article(request, article_id): 2 # #通过article_id参数创建一个BlogArticles类的实例,是读取id值是article_id的记录 3 article = BlogArticles.objects.get(id=article_id) 4 # article = get_object_or_404(BlogArticles, id=article_id) 5 pub = article.publish 6 return render(request,'blog/content.html',{"article":article,"publish":pub})
创建./templates/blog/content.html文件,并输入如下代码。
1 {% extends "base.html" %} 2 3 {% block title %}block article{% endblock %} 4 5 {% block content %} 6 <div class="row text-center vertical-middle-sm"> 7 <h1>{{ article.title }}</h1> 8 </div> 9 <div class="row"> 10 <div class="col-xs-12 col-md-8"> 11 <p class="text-center"><span>{{ article.author.username }}</span><span 12 style="margin-left:20px">{{ publish }}</span></p> 13 <div>{{ article.body }}</div> 14 </div> 15 <div class="col-xs-6 col-md-4"> 16 <h2>广告</h2> 17 <p>跟老齐学:www.itdiffer.com</p> 18 <img width="200px" src="http://www.mrwallpaper.com/wallpapers/Fluffy-Cat.jpg"> 19 </div> 20 </div> 21 {% endblock %}
接着配置URL,不需要修改./mysite/urls.py,只需要在./blog/urls.py文件中增加新的URL路径。
1 path('<int:article_id>/', views.blog_article, name='blog_detail'),
在浏览器打开页面显示如下:
注意:观察网址可以修改最后那个代表文章id的数字。项目中id最大值是3,也就是说总共有3篇文章,如果修改为4或者其他值,这个页面就会变成如下如所示:
因为不存在此id,所以报错。现在处于DEBUG状态,显示了错误的完整信息。为了避免出现上述错误,应该在响应此请求的函数中对这种异常请求进行处理。要适当修改./blog/views.py中的blog_article()函数。代码如下:
1 from django.shortcuts import render,get_object_or_404 #① 2 from .models import BlogArticles 3 4 def blog_article(request, article_id): 5 # #通过article_id参数创建一个BlogArticles类的实例,是读取id值是article_id的记录 6 # article = BlogArticles.objects.get(id=article_id) 7 article = get_object_or_404(BlogArticles, id=article_id) #② 8 pub = article.publish 9 return render(request,'blog/content.html',{"article":article,"publish":pub})
语句①引入了get_object_or_404()方法,能简化对请求网页不存在时的异常处理。当请求对象不存在时,会抛出DoesNotExist异常。这个异常,可以用try...except...捕获,在except中可以使用raise Http404()来处理。我们使用get_object_or_404(),省略了一些代码,此方法的参数列表为get_object_or_404(klass,*args,**kwargs)。
- klass:一般是数据模型中的一个类(Model类)
- *args和**kwargs:查询时的条件参数。
再次请求那个不存在的地址时,就显示404错误了,如下图所示。
至此,一个博客就创建完成了,虽然简陋,但显示了Django在网站开发中的基本结构。
1.3.3 知识点
1、Django的MTV
在动态网站开发中,普遍遵循MVC模式。MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用称为可能。
MVC(Model-View-Controller)模式就是把数据存取逻辑、业务逻辑和表现逻辑组合在一起的模式。在MVC模式中,Model代表数据存取层;View代表系统中选择显示什么和怎么显示的部分;Controller是系统中根据用户输入和需要访问模型,以决定使用哪个视图的部分。MVC模式已经成为网站开发的共识,Django更不例外,或者说Django是一种MVC的框架,具体表现如下:
- M:数据存储和读取部分,由Django的数据模型部分承担。
- V:确定要显示哪些数据及如何显示,由视图和模板进行处理。
- C:根据客户端请求映射到相应的视图,由Django框架根据URLconf设置,调用相应的函数。
在Django中,Controller部分事实上是由框架自动处理的,不需要开发者做什么,于是Django就转变为模型(Model)、模板(Template)和视图(Views)三部分了,可以称之为MTV模式。
- M:模型(Model),即数据存取层,模型是网站项目的基础,主要负责处理与数据相关的事务,如读取、写入数据等。
- T:模板(Template),即表现层,处理与表现有关的事务,例如如何在页面中显示相关内容。
- V:视图(Views),即业务逻辑层,包含存取模型及调取相应模板的相关逻辑,是M(模型)和T(模板)之间的桥梁。当Django得到用户的请求后,根据URL映射关系调用相应的视图,视图则调用和处理有关数据。与模板相比,视图确定访问者能看到哪些数据,而模板确定怎么看到这些数据(或者说用什么方式看到这些数据)。
如下图所示是Django对一个HTTP请求响应的流程图。
从上图可以看到不少“中间件”,这是Django的核心,所有的请求、返回命令都是又中间件来完成的。这些中间件被定义在settings.py的MIDDLEWARE_CLASSES中。
2、Django核心理念
- 更Python化。
- DRY。很重要的原则,即Don't repeat yourself(不要重复自己)。这个原则可以作为所有程序员开发的原则。如允许在数据模型中创建方法实现某些针对该模型实例的常见操作。
- 松耦合与灵活。Django使用MTV模式,实现了数据库访问、业务逻辑、模板显示等层面的松耦合和各自的灵活操作。在模板系统层面,如果用户不喜欢Django的模板系统,可以使用其他的模板系统;在数据库层面,用户可以自由地配置多种数据库,当然也可以不用Django封装的数据库API,而是通过SQL语句直接操作数据库。
- 快速开发。Django在不同层面上都提供了快速开发所需要的工具,不如通用视图。
3、URL配置和查询
浙公网安备 33010602011771号