Django学习笔记 (2)
1. 简单的博客系统
...
2. 用户管理
2.1 自定义模板和静态文件位置
2.1.1 自定义模板位置
2.1.2 自定义静态文件位置
2.1.3 通用静态文件和基础模板
2.1.4 重置管理后台模板
2.1.5 知识点
2.2 用户登录
2.2.1 创建应用
2.2.2 理解表单类
2.2.3 登陆的视图函数
2.2.4 登陆的前端界面
2.2.5 知识点
2.3 用内置方法实现登录和退出
2.3.1 内置的登录方法
2.3.2 判断用户是否登录
2.3.3 内置的退出方法
2.3.4 知识点
2.4 用户注册
2.4.1 简单注册
2.4.2 增加注册内容
2.4.3 管理新增的注册内容
2.4.4 知识点
2.5 关于密码的操作
2.5.1 修改密码
2.5.2 重置密码
2.5.3 利用第三方应用重置密码
2.5.4 知识点
2.6 维护个人信息
2.6.1 个人信息的数据模型类和表单类
2.6.2 展示个人信息
2.6.3 编辑个人信息
2.6.4 上传和裁剪头像图篇
2.6.5 优化头像上传功能
2.6.6 对个人信息进行管理
2.6.7 知识点
3. 文章管理和展示
...
附. 第一章操作步骤速查
安装Django
创建项目
创建应用
修改项目设置
编写数据模型类
迁移生成数据表和数据库
创建超级管理员
运行服务器
进行登录设置
测试“发布文章”功能
丰富列表页的信息
视图(业务逻辑系统) --> 模板文件(展示系统) --> 匹配URL(业务逻辑系统)
2. 用户管理
前言:
首先确定,自己能够根据记忆和理解重建一次第一章的项目和博客应用。然后再开始新学习。
从本章开始,将不再做单一用户的博客网站,而是要一步一步地做一个多用户的文章管理系统。
多用户,首要的是对众多用户进行管理,许可用户注册、登录、退出,并且超级管理员也能够对所有用户进行管理。任何一个大系统都是由许多小功能组成的。
2.1 自定义模板和静态文件位置
依然使用第一章中创建的项目,不过因为是大一点的系统了,所以会创建多个应用,这种情况下模板、静态文件等都要指定放在某个位置。笔者不赞成将模板和静态文件分散到各个应用内,虽然这样也可以,但笔者还有另外一个目的,就是介绍如何在 ./mysite/settings.py 中设置模板和静态文件的位置,以备后用。自定义模板和静态文件位置的基本知识如下如所示:
2.1.1 自定义模板位置
编辑 ./mysite/settings.py 文件,修改 TEMPLATES 的值
(【注】有且仅有语句[1]和[2]两处改动)
TEMPLATES = [
{
'BACKEND':'django.template.backends.django.DjangoTemplates',
'DIRS':[os.path.join(BASE_DIR, 'templates'),],# [1]
'APP_DIRS':False,#[2]
'OPTIONS':{
'context_processors':[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
语句[1]定义了模板文件的位置( ‘./mysite/mysite/’ + 'templates/),并且将该目录的名称 templates 也在这里定义了, BASE_DIR 表示本项目的根目录( ./mysite/mysite/ ),用 os.path.join() 函数将两者连接起来,即模板目录的位置是相对项目根目录的 templates 目录—— ./templates 。显然,读者可以按照自己的意愿来定义模板目录的名称和位置。
语句[2]将 APP_DIRS 设置为 False ,既不再允许 Django 按照默认方式(默认方式为???)寻找模板文件。
根据上述配置要求,在网站根目录建立 templates 目录:
[mysite]$ ls
blog db.sqlite3 manage.py mysite templates
重新运行服务
[mysite]$ python manage.py runserver
浏览器访问 http://localhost:8000/blog ,发现报错,因为我们仅仅建立了一个空文件夹,还没有创建模板。
将文件夹 ./blog/templates/ 中的所有内容移动到 ./mysite/mysite/templates 中,再刷新页面即可。
最后,可以将所有应用的模板都放在 ./templates 中。
2.1.2 自定义静态文件位置
在网站开发中,经常讲网页中的 CSS、JavaScript 文件及网页上的图片称为静态文件——与被渲染的模板文件比较。
打开 ./mysite/settings.py 文件,在最后几行代码中有
# Static files (CSS, JavaScript, Images)
# https://docs.djangoprojects.com/en/dev/howto/static-files/
STATIC_URL = '/static/'
先看上面两行注释的含义,第一行说明了 Django 中认定的静态文件是什么,第二行告诉我们想要知道怎么做可以去查看一个地址。最后一行代码的意思是如果通过 URL 访问静态文件,则可以通过(以刚刚建立的 blog 引用为例子)" http://localhost:8000/ + blog/ + static/ + newton.jpg " 的模式进行访问(类似 [hostname] + [path] + static + [filename] )。要实现这个目的,需要在 ./blog 目录中建立一个名为 static 的目录,然后将静态文件(如 newton.jpg )放在里面。
这种方式让每个应用都有自己的静态文件存放地。在实践中 ,通常也采用与模板文件一样的方式,把所有静态文件都放到指定的目录中。一次,继续编辑 ./mysite/settings.py 文件,在 STATCI_URL=’/static/’ 的下面增加如下代码:
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
通过上述配置,指定了静态文件存放目录的位置,即在项目根目录处建立子目录 /root/mysite/mysite/static/ ,并在该目录中放置一个图片文件,用来测试效果:
[mysite]$ ls
blog db.sqlite3 manage.py media mysite static templates
完成上述操作,需要重新启动 Django 服务,用浏览器再次打开 http://localhost:8000/static/newton.jpg ,是否访问到静态文件了?
之所以能够如此设置,是因为 Django 的 settings.py 配置变量中的 STATICFILES_FINDERS 的默认值规定了静态文件的查找顺序和内容。
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder"
)
按照这个默认值,首先读取 STATICFILES_DIR 中规定的静态文件( django.contrib.staticfiles.finders.FileSystemFinder ),如果没有设置此值,就找不到什么,但不会对网站运行造成影响。然后通过 django.contrib.staticfiles.finders.AppDirectoriesFinder 在每个应用中查找有没有默认的静态文件目录 static 。如果读者在命名时将两处都做了设置,而且静态文件的名字还都一样,name Django 会在找到第一个后终止查询。
将所有的静态文件都归到同一个目录,为了区分不同应用的静态文件,通常还会在里面再建立子目录,后续会看到此类操作。
2.1.3 通用静态文件和基础模板
在第一章的示例中,已经使用了 bootstrap.css 静态文件,但是这个静态文件是放在第三方服务器上的,我们通过网址引用。这样做虽然简单,却不能保证对方永久提供该链接,为此我们需要自己的通用静态文件。
所谓通用静态文件,就是会在很多应用中使用到的,比如 jquery 和 bootstrap 相关文件。先到各自官方网站上下载相应的文件,然后放到已经建立的 static 目录中。为了区分不同类型的文件,要分门别类的建立目录,目录结构如下:
[root@hserver1 static]# tree
├── static
│ ├── css
│ │ ├── bootstrap.css
│ │ ├── bootstrap.css.map
│ │ ├── bootstrap.min.css
│ │ ├── bootstrap.min.css.map # 原版没有
│ │ ├── bootstrap-theme.css
│ │ ├── bootstrap-theme.css.map
│ │ ├── bootstrap-theme.min.css
│ │ └── bootstrap-theme.min.css.map # 原版没有
│ ├── fonts
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2 # 原版没有
│ └── js
│ ├── bootstrap.js
│ ├── bootstrap.min.js
│ ├── jquery.js # jquery.min.js 也可以
│ └── npm.js
这样就将通用的部分静态文件存放好了。还有一些图片,比如网站的 LOGO ,可以放到 images 文件夹里面。
这些通用的静态文件常常在基础模板中使用,比如第一章示例中的 base.html 。针对本章所要创建的项目,我们要重新制作其基础模板。
<!-- ./templates/base.html -->
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title># [5]
<link rel="stylesheet" href="http://necolas.github.io/normalize.css/"># [6]
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css"># [7]
</head>
<body>
<div class="container">
{% block content %}# [8]
{% endblock %}
</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script># [9]
<script src="http://libs.baidu.com/bootstrap/3.0.3/bootstrap.min.js"></script># [10]
</body>
</html>
一般来讲,网站的界面可以大致分为上、中、下三个部分。上部就是头部(header),显示网站的 LOGO 和导航等;中部就是要显示的具体内容(body);下部就是底部(footer),显示网站的版权信息或者诸如联系方式、购买流程等不怎么变化的信息或者超链接。
按照上面的划分,头部和底部都可以做成基础模板。
在 ./templates 目录中创建 header.html 和 footer.html 文件,其中 header.html 文件代码如下:
<!-- header.html -->
{% load staticfiles %}<!--[1]-->
<div class="container">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar=header">
<a class="navbar-brand" href="http://www.itdiffer.com"><img src="{% static '/images/logo.png' %}" width="100px"></a><!--[2]-->
</div>
<div>
<ul class="nav navbar-nav" role="navigation">
<li><a href="{% url 'blog:blog_title' %}">BLOG</a></li><!--[3]-->
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">LOGIN</a></li>
</ul>
</div>
</nac>
</div>
这就是所谓的头部代码(hreder.html)。
语句[1]是模板中声明引入静态文件的标签,只有使用它,语句[2]中才能使用 {% static ‘images/logo.png’ %} ,而不是用“硬编码”的方式写图片地址。语句[2]中的这个写法也是 Django 模板的一个语法, {% static %} 可以用来引入某个静态文件,此处表示引入了静态文件中的一张图片,注意使用格式和引用路径。语句[1]写在语句[2]前面即可,此处之所以写在顶部,只是习惯使然,并非一定。
【注】硬编码:如果在开发中,在某个需要做超链接的地方使用了类似
<a href="course/38">Django</a>
的方式,则随着 URL 目录结构发生变化,这个超链接将报错。这种就称之为“硬编码”。
语句[3]中的 {% url ‘blog:blog_title’ %} 使用了在 ./mysite/urls.py 的 URLconf 中为应用设置的 namespace 和相关应用中的 name 值,拼接成该应用的入口链接 URL 。这样做同样是要避免“硬编码”。
【注】 难以理解blog_title是视图文件里的函数,但正常顺序是 视图调用模板,那么模板怎么能反调用视图的内容呢???
这里的 footer.html 代码就相当简约了:
<!-- footer.html -->
<div class="container">
<hr>
<p class="text-center">copy right www.itdiffer.com</p>
</div>
头部代码编写完之后,把他们放到一个 base.html 的文件中进行整合,这个文件在前面已经创建了,此处结合刚才编写 header.html 和 footer.html 文件,将 base.html 文件重写:
<!-- base.html -->
{% load staticfiles %}
<!DOCTYPE html>
<html lang=“zh-cn"”>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}">
</head>
<body>
{% include "header.html" %}
<div class="container">
{% block content %}{% endblock %}
</div>
{% include "footer.html" %}
{% block javascript %}{% endblock %}
</body>
</html>
关于应用 blog 本身的模板就不需要做任何修改了。重启 Django 服务器,访问 http://localhost:8000/blog/ ,即可看到章节1.3.1 中的页面“显示文章标题”。
2.1.4 重置管理后台模板
现在再次访问 http://localhost:8000/admin/ ,将发现报错“找不到模板 ./templates/admin/index.html ”,这是因为我们已经将默认的文件模板位置都指向了自定义的模板位置,但里面还没有后台管理所对应的模板。
Template-loader postmortem
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.filesystem.Loader:
/home/qiwsir/DjangoPracticeProject/mysite/templates/admin/index.html (Source does not
exist)
下一步将后台管理的模板放入自定义模板位置中,一共有两个—— admin 和 registration ,他们都在 Django 的安装目录的 ./contrib/admin/templates 里。复制过来即可。
2.1.5 知识点
.1 模板
前面已经在开发过程中用到模板了,这里对相关知识进行总结归纳。 Django 中的模板本质上也是一个独立的文本文件(其实不仅是 Django ,其他的 Web 框架模板也是如此),文件中包含了静态内容(比如 HTML , CSS )和动态标记的数据。 DJango 中的视图函数(或者视图类)决定了哪个模板(例如"blog/title.html")以及向模板渲染什么数据(例如"{‘blogs’:blogs}")。
编写模板所用的语言以 HTML , CSS , JavaScript 为主。模板不是嵌入 Python 语言,但是为了增强其表现力,里面也会通过一些模板语言来实现类似循环那样的逻辑,例如:
{% for blog in blogs %}# [14]
<li>{
{blog.title}}</li># [15]
{% endfor %}
.2 contexts
contexts 目前不方便直译,读者可以把它看做一个专有名词。
模板是一个动态文档,只有在显示动态信息时才能感受到他的存在。 Django 的视图函数在渲染模板(将有关数据传给模板)时使用的中介物就是 contexts 。contexts 是一个包含了键值对的字典,例如前面曾经使用过的
return render(request, "bolg/title.html", {"article":article, "publish":pub})
这条代码通过 render() 函数声明了所使用的模板—— “bolg/title.html” ,和contexts—— {“article”:article, “publish”:pub} 。在 contexts 的键值对中,“键”是传给模板的变量,这个变量可以引用任何在视图函数中确定的对象。
.3 模板: for 和 if
所为模板语法,就是根据 Django 的规定,在模板中使用通过 contexts 传入模板的数据对象。一般情况下有两种语法,一类是单独的变量,也称为变量标签;另一类是块命令,也称为块便签。
例如,前面使用的 {
{publish}} 就是变量标签, publish 是 contexts 中的一个“键”,通过它将 contexts 键值对中的值传入模板,即在该位置显示所渲染的数据内容。注意,这种变量标签必须用 {
{variable}} 的形式——使用双花括号(大括号)。
【注】即“ contexts 中的键对应模板中的变量名,值对应视图文件中的变量名
除了变量标签外,还有“块便签”,下面的代码实现 for 循环,就是一种块标签:
{% for blog in blog %}
<li><a href="{
{blog.id}}">{
{blog.t itle}}</a></li>
{% endfor %}
块标签以 {% command %} 开头( {% for blog in blogs %} ),并以 {% endname %} 结尾( {% endfor %} ),中间是块的内容,上例中的 { {blog.title}} 依然是变量标签,只不过这个变量的内容来自 contexts 的键 blog 应用的对象的一个属性( title )。
对于 for 循环标签,在模板中应用时,常常会使用循环计数功能,为此 Django 模板提供了默认的 { { forloop.counter }} 从1开始技术的方式,不需要视图函数中的 contexts 提供 forloop 键值对,只要是模板中的循环,都可以使用这样的方法实现对被循环内容的计数功能。另外,还有 { {forloop.counter() }} 是从零开始计数。
在模板中可以实现 for 循环外,还可以实现 if 循环,其样式如下:
{% if condition %}
something
{% endif %}
注意,在 Django 模板的 if 标签中也有类似 Python 的 if…else 结构:
{% if condition %}
something
{% else %}
others
{% endif %}
以上两种标签在模板中比较常用,而且他们也能够被嵌套使用。
.4 文档导读
.4.1 Managing static files1
.4.2 The Django template language2
.4.3 Built-in template tag and filters3
2.2 用户登录
前面我们创建了一个超级管理员用户 admin (当然也可以命名为其他名称),并且可以通过管理员登录页面( http://localhost:8000/admin/ )登录到管理后台,而且在这个后台发布了博客。
注意到这个后台由用户管理功能,有且仅有管理员admin可以通过后台的 Users 选项向本网站中增加用户。
对于一个多用户的文章系统,非管理员用户最好是从前台登录,登录之后仅具有所规定的功能。
下面首先解决登陆问题,如下图所示: