一 Django Admin 管理工具
Django 提供了基于 web 的管理工具。
Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它:
1 | INSTALLED_APPS = ( |
django.contrib是一套庞大的功能集,它是Django基本代码的组成部分。
1. 激活管理工具
通常我们在生成项目时会在 urls.py 中自动设置好,我们只需去掉注释即可。
配置项如下所示:
1 | # urls.py |
启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/,得到如下界面:
你可以通过命令 python manage.py createsuperuser 来创建超级用户,如下所示:
1 | # python manage.py createsuperuser |
输入用户名密码后如图所示
为了让 admin 界面管理某个数据模型,我们需要先注册该数据模型到 admin。比如,我们之前在 TestModel 中已经创建了模型 Test 。修改 TestModel/admin.py:
1 | from django.contrib import admin |
刷新后即可看到 Testmodel 数据表:
2 复杂模型
管理页面的功能强大,完全有能力处理更加复杂的数据模型。
先在 TestModel/models.py 中增加一个更复杂的数据模型:
1 | from django.db import models |
这里有两个表。Tag 以 Contact 为外部键。一个 Contact 可以对应多个 Tag。
我们还可以看到许多在之前没有见过的属性类型,比如 IntegerField 用于存储整数。
在 TestModel/admin.py 注册多个模型并显示:
1 | from django.contrib import admin |
刷新管理页面,显示结果如下:
3 自定义表单
我们可以自定义管理页面,来取代默认的页面。比如上面的 “add” 页面。我们想只显示 name 和 email 部分。修改 TestModel/admin.py:
1 | from django.contrib import admin |
以上代码定义了一个 ContactAdmin 类,用以说明管理页面的显示格式。
里面的 fields 属性定义了要显示的字段。
由于该类对应的是 Contact 数据模型,我们在注册的时候,需要将它们一起注册。显示效果如下:
我们还可以将输入栏分块,每个栏也可以定义自己的格式。修改 TestModel/admin.py为:
4 内联(Inline)显示
上面的 Contact 是 Tag 的外部键,所以有外部参考的关系。
而在默认的页面显示中,将两者分离开来,无法体现出两者的从属关系。我们可以使用内联显示,让 Tag 附加在 Contact 的编辑页面上显示。
修改TestModel/admin.py:
1 | from django.contrib import admin |
二、Django ORM - 单表实例
阅读本章节前你需要先阅读了 Django 模型 进行基础配置及了解常见问题的解决方案。
接下来我们重新创建一个项目 app01(如果之前已创建过,忽略以下操作):
1 | django-admin startapp app03 |
接下来在 settings.py 中找到 INSTALLED_APPS 这一项,如下:
1 | INSTALLED_APPS = ( |
接下来,告诉 Django 使用 pymysql 模块连接 mysql 数据库:
1 | # 在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置 |
1 创建模型
在项目中的 models.py 中添加以下类:
app03/moudels.py
1 | class Book(models.Model): |
然后在命令行执行以下命令:
1 | #$ python3 manage.py migrate # 创建表结构 如果前面有过就不用运行这句话了 |
2 数据库添加
规则配置:
apo03/urls.py
1 | from django.contrib import admin |
views.py
1 | from django.shortcuts import render,HttpResponse |
创建 | creat | models.Book.objects.create(title=”如来神掌”,price=200,publish=”功夫出版社”,pub_date=”2010-10-10”) |
---|---|---|
查找all全部 | all | books = models.Book.objects.all() |
filter符合条件 | models.Book.objects.filter(pk=5) | |
models.Book.objects.filter(publish=’菜鸟出版社’, price=300) | ||
exclude不符合条件 | books = models.Book.objects.exclude(pk=5) | |
排序 | order_by() | books = models.Book.objects.order_by(“price”) # 查询所有,按照价格升序排列 |
books = models.Book.objects.order_by(“-price”) # 查询所有,按照价格降序排 | ||
反转 | reverse() | books = models.Book.objects.order_by(“-price”).reverse() |
计数 | count() | books = models.Book.objects.count() # 查询所有数据的数量 |
books = models.Book.objects.filter(price=200).count() # 查询符合条件数据 | ||
是否存在 | exists() | books = models.Book.objects.exists() |
# 报错,判断的数据类型只能为QuerySet类型数据,不能为整型
books = models.Book.objects.count().exists()
# 报错,判断的数据类型只能为QuerySet类型数据,不能为模型类对象
books = models.Book.objects.first().exists() |
| 查询 | values() | # 查询所有的id字段和price字段的数据
books = models.Book.objects.values(“pk”,”price”) |
| 对数据进行去重 | distinct() | books = models.Book.objects.values_list(“publish”).distinct() # 对模型类的对象去重没有意义,因为每个对象都是一个不一样的存在。
books = models.Book.objects.distinct() |
| 符号 | __gt 大于号 | books = models.Book.objects.filter(price__gt=200) |
| | __gte 大于等于 | books = models.Book.objects.filter(price__gte=200) |
| | __lt 小于 | books=models.Book.objects.filter(price__lt=300) |
| | __lte 小于等于 | books=models.Book.objects.filter(price__lte=300) |
| | __range | models.Book.objects.filter(price__range=[200,300]) |
| | __contains | models.Book.objects.filter(title__contains=”菜”) |
| | __icontains | models.Book.objects.filter(title__icontains=”python”) |
| | __startswith | models.Book.objects.filter(title__startswith=”菜”) |
| | __endswith | models.Book.objects.filter(title__endswith=”教程”) |
| | __year | models.Book.objects.filter(pub_date__year=2008) |
| 删除 | 类型数据.delete() | models.Book.objects.filter(pk__in=[1,2]).delete() |
| 修改 | 类型数据.update(字段名=更改的数据) | books = models.Book.objects.filter(pk__in=[7,8]).update(price=888) |
三、Django ORM – 多表实例
略
https://www.runoob.com/django/django-orm-2.html
四、Django ORM – 多表实例(聚合与分组查询)
略
https://www.runoob.com/django/django-orm-3.html
五、Django Form 组件
https://www.runoob.com/django/django-form-component.html
略
六、Django 用户认证(Auth)组件
Django 用户认证(Auth)组件一般用在用户的登录注册上,用于判断当前的用户是否合法,并跳转到登陆成功或失败页面。
Django 用户认证(Auth)组件需要导入 auth 模块:
1 | # 认证模块 |
返回值是用户对象。
创建用户对象的三种方法:
- **create()**:创建一个普通用户,密码是明文的。
- **create_user()**:创建一个普通用户,密码是密文的。
- **create_superuser()**:创建一个超级用户,密码是密文的,要多传一个邮箱 email 参数。
参数:
- username: 用户名。
- password:密码。
- email:邮箱 (create_superuser 方法要多加一个 email)。
注意一定要使用create_user,如果使用create会导致密码是以明文的形式存储在数据库里,从而导致后面authenticate认证出错
1 | from django.contrib.auth.models import User |
登录
原文里面没有加最后一行导致一直在报错,一定要注意请求一定要返回一个可处理的对象。
1 | def login(request): |
login.html
1 | <!DOCTYPE html> |
七 Django cookie 与 session
Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。
识别返回用户包括三个步骤:
- 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。
- 浏览器将这些信息存储在本地计算机上,以备将来使用。
- 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。
HTTP 是一种”无状态”协议,这意味着每次客户端检索网页时,客户端打开一个单独的连接到 Web 服务器,服务器会自动不保留之前客户端请求的任何记录。
但是仍然有以下三种方式来维持 Web 客户端和 Web 服务器之间的 session 会话
1 Cookies
一个 Web 服务器可以分配一个唯一的 session 会话 ID 作为每个 Web 客户端的 cookie,对于客户端的后续请求可以使用接收到的 cookie 来识别。
在Web开发中,使用 session 来完成会话跟踪,session 底层依赖 Cookie 技术。
a Django 中 Cookie 的语法
设置 cookie:
1 | rep.set_cookie(key,value,...) |
获取 cookie:
1 | request.COOKIES.get(key) |
删除 cookie:
1 | rep =HttpResponse || render || redirect |
b 创建应用和模型
models.py
1 | class UserInfo(models.Model): |
urls.py
1 | from django.contrib import admin |
views.py
1 | def login(request): |
以下创建三个模板文件:login.html、index.html、order.html
login.html
1 | <!DOCTYPE html> |
index.html
1 | <!DOCTYPE html> |
order.html
1 | <!DOCTYPE html> |
2 Session(保存在服务端的键值对)
服务器在运行时可以为每一个用户的浏览器创建一个其独享的 session 对象,由于 session 为用户浏览器独享,所以用户在访问服务器的 web 资源时,可以把各自的数据放在各自的 session 中,当用户再去访问该服务器中的其它 web 资源时,其它 web 资源再从用户各自的 session 中取出数据为用户服务。
工作原理
a. 浏览器第一次请求获取登录页面 login。
b. 浏览器输入账号密码第二次请求,若输入正确,服务器响应浏览器一个 index 页面和一个键为 sessionid,值为随机字符串的 cookie,即 set_cookie (“sessionid”,随机字符串)。
c. 服务器内部在 django.session 表中记录一条数据。
django.session 表中有三个字段。
- session_key:存的是随机字符串,即响应给浏览器的 cookie 的 sessionid 键对应的值。
- session_data:存的是用户的信息,即多个 request.session[“key”]=value,且是密文。
- expire_date:存的是该条记录的过期时间(默认14天)
d. 浏览器第三次请求其他资源时,携带 cookie :{sessionid:随机字符串},服务器从 django.session 表中根据该随机字符串取出该用户的数据,供其使用(即保存状态)。
注意: django.session 表中保存的是浏览器的信息,而不是每一个用户的信息。 因此, 同一浏览器多个用户请求只保存一条记录(后面覆盖前面),多个浏览器请求才保存多条记录。
cookie 弥补了 http 无状态的不足,让服务器知道来的人是”谁”,但是 cookie 以文本的形式保存在浏览器端,安全性较差,且最大只支持 4096 字节,所以只通过 cookie 识别不同的用户,然后,在对应的 session 里保存私密的信息以及超过 4096 字节的文本。
session 设置:
1 | request.session["key"] = value |
执行步骤:
- a. 生成随机字符串
- b. 把随机字符串和设置的键值对保存到 django_session 表的 session_key 和 session_data 里
- c. 设置 cookie:set_cookie(“sessionid”,随机字符串) 响应给浏览器
session 获取:
1 | request.session.get('key') |
执行步骤:
- a. 从 cookie 中获取 sessionid 键的值,即随机字符串。
- b. 根据随机字符串从 django_session 表过滤出记录。
- c. 取出 session_data 字段的数据。
session 删除,删除整条记录(包括 session_key、session_data、expire_date 三个字段):
1 | request.session.flush() |
删除 session_data 里的其中一组键值对:
1 | del request.session["key"] |
执行步骤:
- a. 从 cookie 中获取 sessionid 键的值,即随机字符串
- b. 根据随机字符串从 django_session 表过滤出记录
- c. 删除过滤出来的记录
八 Django 中间件
Django 中间件是修改 Django request 或者 response 对象的钩子,可以理解为是介于 HttpRequest 与 HttpResponse 处理之间的一道处理过程。
浏览器从请求到响应的过程中,Django 需要通过很多中间件来处理,可以看如下图所示:
Django 中间件作用:
- 修改请求,即传送到 view 中的 HttpRequest 对象。
- 修改响应,即 view 返回的 HttpResponse 对象。
中间件组件配置在 settings.py 文件的 MIDDLEWARE 选项列表中。
配置中的每个字符串选项都是一个类,也就是一个中间件。
Django 默认的中间件配置:
1 | MIDDLEWARE = [ |
1 自定义中间件
中间件可以定义四个方法,分别是:
1 | process_request(self,request) |
自定义中间件的步骤:
在 app 目录下新建一个 py 文件,名字自定义,并在该 py 文件中导入 MiddlewareMixin:
1 | **from django.utils.deprecation import MiddlewareMixin** |
自定义的中间件类,要继承父类 MiddlewareMixin:
1 | class MD1(MiddlewareMixin): |
在 settings.py 中的 MIDDLEWARE 里注册自定义的中间件类:
1 | MIDDLEWARE = [ |
2 自定义中间件类的方法
自定义中间件类的方法有:process_request 和 process_response。
a process_request 方法
process_request 方法有一个参数 request,这个 request 和视图函数中的 request 是一样的。
process_request 方法的返回值可以是 None 也可以是 HttpResponse 对象。
- 返回值是 None 的话,按正常流程继续走,交给下一个中间件处理。
- 返回值是 HttpResponse 对象,Django 将不执行后续视图函数之前执行的方法以及视图函数,直接以该中间件为起点,倒序执行中间件,且执行的是视图函数之后执行的方法。
process_request 方法是在视图函数之前执行的。
当配置多个中间件时,会按照 MIDDLEWARE中 的注册顺序,也就是列表的索引值,顺序执行。
不同中间件之间传递的 request 参数都是同一个请求对象。
1 | from django.utils.deprecation import MiddlewareMixin |
b process_response
process_response 方法有两个参数,一个是 request,一个是 response,request 是请求对象,response 是视图函数返回的 HttpResponse 对象,该方法必须要有返回值,且必须是response。
process_response 方法是在视图函数之后执行的。
当配置多个中间件时,会按照 MIDDLEWARE 中的注册顺序,也就是列表的索引值,倒序执行。
1 | class MD1(MiddlewareMixin): |
从下图看,正常的情况下按照绿色的路线进行执行,假设中间件1有返回值,则按照红色的路线走,直接执行该类下的 process_response 方法返回,后面的其他中间件就不会执行。
c process_view
process_view 方法格式如下:
1 | process_view(request, view_func, view_args, view_kwargs) |
process_view 方法有四个参数:
- request 是 HttpRequest 对象。
- view_func 是 Django 即将使用的视图函数。
- view_args 是将传递给视图的位置参数的列表。
- view_kwargs 是将传递给视图的关键字参数的字典。
view_args 和 view_kwargs 都不包含第一个视图参数(request)。
process_view 方法是在视图函数之前,process_request 方法之后执行的。
返回值可以是 None、view_func(request) 或 HttpResponse 对象。
- 返回值是 None 的话,按正常流程继续走,交给下一个中间件处理。
- 返回值是 HttpResponse 对象,Django 将不执行后续视图函数之前执行的方法以及视图函数,直接以该中间件为起点,倒序执行中间件,且执行的是视图函数之后执行的方法。
- c.返回值是 view_func(request),Django 将不执行后续视图函数之前执行的方法,提前执行视图函数,然后再倒序执行视图函数之后执行的方法。
- 当最后一个中间件的 process_request 到达路由关系映射之后,返回到第一个中间件 process_view,然后依次往下,到达视图函数。