django教程

Django基础

Django是一个高级的Python Web开发框架,它采用了MVC(Model-View-Controller)的软件设计模式,旨在帮助开发人员快速构建高质量的Web应用程序。

Django的特点

特点 描述
强大的ORM 提供了一个强大的对象关系映射层,简化数据库操作
完整的功能集 内置了许多常用的功能,如身份验证、URL路由、表单处理等
自动化的管理界面 自动生成管理界面,方便管理数据库模型和数据
灵活的模板系统 支持模板继承、条件逻辑、循环和变量插值等功能
强调代码复用 通过模块化和组件化的设计,促进代码复用和可维护性
丰富的第三方生态系统 庞大的社区支持,提供了大量的插件、应用和开源项目
高度可扩展性 支持插件和第三方应用的集成,方便扩展和定制化开发
强调安全性 提供了多种安全机制和防护措施,保护Web应用的安全性
广泛的应用领域 适用于构建各种类型的Web应用程序,从小型网站到大型应用平台
全面的文档和支持 提供了全面的官方文档和教程,社区活跃,有很多资源和解决方案可用

本教程使用软件版本

软件名称 版本
python 3.11.0
django 4.2.1

Django安装与配置

安装python虚拟环境

sudo pip install virtualenv
python3.11 -m venv --copies venv3.11

加载虚拟环境并安装django

source venv3.11/bin/activate
pip install django

创建名为pydj的django项目和api的应用

django-admin startproject pydj
django-admin startapp api

项目目录结构

pydj
├── api
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── pydj
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py

调整pydj/pydj目录为pydj/config;编辑manage.py文件中main函数以下参数:

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')

编辑pydj/config/settings.py文件以下参数:

ROOT_URLCONF = 'config.urls'
WSGI_APPLICATION = 'config.wsgi.application'

再次查看django目录结构

pydj
├── api
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── config
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-38.pyc
│   │   ├── settings.cpython-38.pyc
│   │   ├── urls.cpython-38.pyc
│   │   └── wsgi.cpython-38.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
└── manage.py

运行django项目

python manage.py runserver

路由

在Django中,路由(Routing)是指将URL请求映射到相应的视图函数或类视图的过程。Django使用URLconf(URL配置)来定义应用程序的路由规则。
URLconf是一个Python模块,它包含了URL模式(URL patterns)和视图函数或类视图之间的映射关系。当用户在浏览器中输入一个URL时,Django的路由系统会根据URLconf中定义的规则,找到匹配的URL模式,并将请求转发给相应的视图处理函数。

路由基本语法

from django.urls import path

urlpatterns = [
path(正则表达式,views视图函数)
]

路由模式

模式 匹配规则
path 使用简单的字符串匹配路径,不支持正则表达式
re_path 使用正则表达式匹配路径,可以捕获参数作为视图函数的参数
include 引入其他应用程序的URLconf,用于实现嵌套路由
redirect 重定向到其他URL
reverse 根据给定的视图名称或URL模式名称生成URL
resolve 根据给定的URL解析到相应的视图函数或类视图
namespace 为应用程序指定命名空间,用于区分不同应用程序的URLconf

案例

URL模式 匹配规则
^articles$ articles开头,以articles结尾,严格限制路径
^(?P<year>[0-9]{4})/$ 以四位数字开头,以斜杠结尾,捕获年份作为参数
^post/(?P<slug>[-\w]+)/$ post/开头,以斜杠结尾,捕获URL中的slug作为参数
^blog/(?P<category>[\w]+)/$ blog/开头,以斜杠结尾,捕获URL中的category作为参数
^users/(?P<username>[\w]+)/profile/$ users/开头,以/profile/结尾,捕获URL中的username作为参数

分组命名匹配

分组命名匹配是一种在正则表达式中使用括号进行分组,并为每个分组指定一个名称的技术。它允许在正则表达式匹配期间捕获和提取特定部分的值,并为每个部分分配一个有意义的名称。 通常,在正则表达式中使用括号创建分组,以便在匹配期间捕获相关的值。

示例

下面url分组命名匹配详细介绍:

URL模式 视图函数 访问示例
r'articles/(?P<year>[0-9]{4})' aaa(request, year) /articles/2022/
r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$' bbb(request, year, month) /articles/2022/05/
r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$' ccc(request, year, month, day) /articles/2022/05/15/

第一行的URL模式为 articles/(?P<year>[0-9]{4}),使用了命名参数 year,对应的视图函数是 aaa(request, year)。访问示例是 /articles/2022/,其中年份为 2022
第二行的URL模式为 ^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$,使用了命名参数 yearmonth,对应的视图函数是 bbb(request, year, month)。访问示例是 /articles/2022/05/,其中年份为 2022,月份为 05
第三行的URL模式为 ^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$,使用了命名参数 yearmonthday,对应的视图函数是 ccc(request, year, month, day)。访问示例是 /articles/2022/05/15/,其中年份为 2022,月份为 05,日期为 15

from django.conf.urls import url
from .import views

urlpatterns = [
url(r'articles/(?P<year>[0~9]{4})', views.aaa) #匹配某年的,(?P<year>[0-9]{4})这是命名参数。那么函数aaa(request,year),形参名称必须是year这个名字。
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.bbb),#某年某月的,那么函数bbb(request,year,month),形参名称必须是year,month这个名字
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.ccc), #某年某月某日
]

路由分发

在Django中,include()函数用于进行路由分发,它允许你将URL配置模块化,将不同的URL模式分发给不同的子路由模块进行处理。比如:有多个应用,app01、app02、app03;在include定义分发到对应的应用,然后在app中定义url子路由转发到对应的视图函数

示例

from django.urls import include, path

urlpatterns = [
# 主页URL
path('', include('myapp.urls')), # 将主页的URL分发给myapp应用程序的urls.py进行处理
# 其他URL模式
]

路由命名空间

当多个应用程序或模块具有相同的URL名称时,Django会根据其所属的路由命名空间来区分它们。通过为每个应用程序或模块定义一个唯一的命名空间,可以确保URL名称的唯一性,并且可以在模板中引用正确的URL。
示例:

# myapp/urls.py
from django.urls import path

app_name = 'myapp' # 定义应用程序的路由命名空间

urlpatterns = [
path('home/', views.home, name='home'), # 给URL模式指定名称为 'home',属于应用程序的命名空间
# 其他URL模式
]

模型

在Django中,模型(Model)是定义数据结构的Python类,用于与数据库进行交互。模型定义了数据表的结构、字段以及相关的行为,允许开发人员使用面向对象的方式来操作数据库。
Django的模型使用了对象关系映射(Object-Relational Mapping,ORM)的概念,它允许你通过操作模型对象来进行数据库的增删改查操作,而无需直接编写SQL语句。
通过定义模型,你可以创建数据库表格,并指定每个表格的字段、关联关系、验证规则等。模型类可以包含字段、方法和元数据,用于描述数据的结构和行为。

ORM的特点

优点 描述
抽象化 ORM屏蔽了数据库底层细节,开发人员可以使用面向对象的方式操作数据,而无需关心底层数据库操作和SQL语句的编写。
简化开发 ORM提供了简洁的API和工具,加速开发过程,减少重复性工作,提高开发效率。
跨数据库支持 ORM通常支持多种数据库系统,开发人员可以在不同的数据库之间切换而无需修改大量代码。
数据库迁移 ORM提供了数据库迁移工具,可轻松进行数据库结构的变更和迁移,维护数据库的一致性和完整性。
数据一致性 ORM通过事务管理确保数据的一致性,提供了高级的事务控制和数据完整性保护机制。
可移植性 由于ORM屏蔽了底层数据库细节,应用程序更易于迁移和部署到不同的环境和平台。
性能优化 ORM框架通常提供了性能优化选项,如缓存机制、延迟加载等,可提升应用程序的响应速度和性能。
代码可读性 使用ORM可以以面向对象的方式操作数据库,使代码更易于理解和维护,提高代码的可读性和可维护性。
协作开发 ORM使得多人协作开发更加容易,开发人员可以根据对象模型进行协作,而不需要处理复杂的SQL语句和数据库操作。
测试和调试 ORM框架通常提供了模拟数据库环境的功能,使得单元测试和调试更加便捷,可以快速验证和修复问题。

模型类与ORM数据库对应关系

类对象 表行
类属性 表字段

模型类ORM字段

ORM字段 描述
AutoField 自动递增的整数字段
BigAutoField 自动递增的大整数字段
CharField 字符串字段
TextField 文本字段
IntegerField 整数字段
BigIntegerField 大整数字段
SmallIntegerField 小整数字段
PositiveIntegerField 正整数字段
PositiveSmallIntegerField 正小整数字段
FloatField 浮点数字段
DecimalField 十进制数字段
BooleanField 布尔字段
NullBooleanField 可为空的布尔字段
DateField 日期字段
DateTimeField 日期时间字段
TimeField 时间字段
DurationField 时间间隔字段
FileField 文件字段
ImageField 图像字段
ForeignKey 外键字段
OneToOneField 一对一关系字段
ManyToManyField 多对多关系字段

模型类ORM字段参数

参数 描述
max_length 字符串字段的最大长度
blank 字段是否允许为空
null 字段是否可以存储NULL值
default 字段的默认值
primary_key 字段是否为主键
unique 字段是否唯一
verbose_name 字段的可读性描述
help_text 字段的帮助文本
choices 字段的选项列表
db_index 字段是否需要在数据库中创建索引
db_column 字段在数据库中的列名
auto_now 每次保存模型时,自动更新字段的值为当前时间
auto_now_add 创建模型时,自动设置字段的值为当前时间
validators 字段的验证器列表
related_name 关联字段在关联模型中的反向引用名称
on_delete 外键字段在关联对象被删除时的处理方式
to_field 外键字段关联的目标模型中用于匹配的字段名称
related_query_name 用于查询关联对象的名称
upload_to 文件字段的上传路径

模型类Meta属性

模型类Meta属性主要用来设置数据库表相关属性

Meta 属性 描述
db_table 指定模型对应的数据库表名称
ordering 模型对象的默认排序方式
verbose_name 模型的可读性描述
verbose_name_plural 模型的复数形式可读性描述
app_label 指定模型所属的应用程序名称
db_alias 指定使用的数据库别名
abstract 声明模型类为抽象基类,该模型类不能被直接实例化
unique_together 指定字段的组合必须是唯一的
indexes 指定模型的数据库索引
constraints 指定模型的数据库约束
default_related_name 关联模型对象的默认反向关联名称
base_manager_name 指定模型类使用的基础管理器名称
default_manager_name 指定模型类使用的默认管理器名称
managed 指定是否由Django自动创建数据库表格,默认为True
get_latest_by 指定按照某个字段的值进行最新对象查询
permissions 指定模型的权限配置
default_permissions 指定模型的默认权限配置
indexes 指定模型的数据库索引
constraints 指定模型的数据库约束

ORM on_delete级联模式参数

on_delete级联模式就是当删除关联表中的数据时,当前表与其关联的行为

on_delete 参数 描述
CASCADE 级联删除关联对象
PROTECT 阻止删除关联对象
SET_NULL 将关联字段设为 NULL
SET_DEFAULT 将关联字段设为默认值
SET(value) 将关联字段设为指定的值
SET(…) 将关联字段设为特定的值或调用指定的方法
DO_NOTHING 什么也不做,保留关联对象而不进行任何操作
RESTRICT 阻止删除关联对象(与 PROTECT 类似)

ORM多表关系

多表关系,相当于数据库表字段的一对一、一对多、多对多

关系类型 描述
一对一关系(One-to-One) 每个对象只能与另一个对象建立一对一的关系
一对多关系(One-to-Many) 一个对象可以关联多个对象,而多个对象只能关联到一个对象
多对一关系(Many-to-One) 多个对象可以关联到一个对象,而一个对象可以关联多个对象
多对多关系(Many-to-Many) 多个对象之间可以相互关联,一个对象可以关联多个对象,多个对象也可以关联到同一个对象

配置原生SQL

在Django settings配置文件中设置logger日志,在执行视图函数的时候可以打印完整的执行sql语句,示例:

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}

ORM单表操作

设计数据库表

字段名称 类型 描述
book_name 字符串 书籍名称
price 浮点数 价格
publish_date 日期 出版日期
publisher 字符串 出版社
stock 整数 库存数量

模型类设计

在应用models.py中定义模型类对象

from django.db import models

class Book(models.Model):
book_name = models.CharField(max_length=100)
price = models.FloatField()
publish_date = models.DateField()
publisher = models.CharField(max_length=100)
stock = models.IntegerField()

def __str__(self):
return self.book_name

模型类定义完成之后在项目config/settings.py中安装应用,应用api一般添加到INSTALLED_APPS列表最后一个元素

INSTALLED_APPS = [
'api'
]

执行数据库迁移操作,该操作会将django模型类对象翻译为数据库sql语句并执行创建数据库表和字段及字段约束

python manage.py makemigrations 
python manage.py migrate

增加数据

在视图api/views.py中定义视图函数,当访问url时,url会根据url匹配规则转发到对应视图函数并执行该视图函数完成数据库添加数据的操作

增加数据内置方法

方法 示例 描述
save() models.Book(field1=value1, field2=value2, ...).save() 保存对象到数据库。
create() models.Book.objects.create(field1=value1, ...).save() 创建并保存对象到数据库。

示例:

import datetime
from django.shortcuts import HttpResponse
from . import models

def add_book(request):

#方式一:定义要添加的数据
book_obj = models.Book(
name = '阿才的博客',
price = '100.00',
public_date = datetime.datetime.now(),
total = 99,
book_status = False
)
#保存数据
book_obj.save()
#方式二:定义要添加的数据
book_obj = models.Book.objects.create(
name = '测试数据',
price = '99.99',
public_date = datetime.datetime.now(),
total = 101,
book_status = True
)
#保存数据
book_obj.save()
#方式三:批量添加多条数据
models.Book.objects.bulk_create(book_obj)
return HttpResponse(book_obj)

查询数据

查询数据内置方法

方法 示例 描述
all() Model.objects.all() 查询所有结果,结果是QuerySet类型
get(**kwargs) Model.objects.get(id=1) 返回与给定筛选条件匹配的对象,结果返回单个对象
filter(**kwargs) Model.objects.filter(name='John') 筛选匹配对象,结果是QuerySet类型
exclude(**kwargs) Model.objects.exclude(age__lt=30) 排除匹配条件的对象,结果是QuerySet类型
order_by(field) Model.objects.order_by('name') 对查询结果进行排序,结果是QuerySet类型
reverse() queryset.reverse() 对查询结果反向排序,结果是QuerySet类型
count() Model.objects.count() 返回匹配查询对象的数量,结果是数字
first() queryset.first() 返回第一条记录对象,结果是模型对象
last() queryset.last() 返回最后一条记录对象,结果是模型对象
exists() queryset.exists() 如果QuerySet中存在数据返回True,否则返回False
values(*field) queryset.values('name', 'age') 返回字典类型数据,包含指定字段的查询结果
values_list(*field) queryset.values_list('name', 'age') 返回元组的QuerySet序列,包含指定字段的查询结果
distinct() queryset.distinct() 去重,去除重复的查询结果

案例

from django.shortcuts import HttpResponse
from . import models

def get_books(requests):
res = models.Book.objects.all()
#获取一条数据
res1 = models.Book.objects.get(id=1)
return HttpResponse(res)

过滤数据

ORM使用filter()函数用来过滤查询字段

示例

def get_books(request):
#filter()过滤查询,相当于sql select * from django where id ='1';
obj = models.Book.objects.filter(id=1)
print obj
return HttpResponse(obj)

更新数据

使用赋值方式更新数据

def update_book(request):
obj = models.Book.objects.get(id='2')
print obj
obj.name = '测试修改数据'
obj.price = 112.95
obj.save()
return HttpResponse(obj)

使用filter过滤要更新的数据然后调用update方法更新数据

def update_book(request):
#update方法,调用者可以是object控制器,也可以是queryset类型数据,不能是模型类对象。
models.Book.objects.filter(publish='xxx出版社').update(
title = 'xxx书籍'
)
return HttpResponse('ok')

删除数据

删除一条数据

def del_book(request):
obj = models.Book.objects.get(id=1).delete()
#返回受影响数据行数
return HttpResponse('del ok')

删除多条数据

def del_book(request):
#删除多条数据
obj = models.Book.objects.filter(book_status=1).delete()
print obj
return HttpResponse('del ok')

清除数据

def duoduiduo_clear(request):
book_obj = models.Book.objects.get(id=3)
#将id为3的数据集对应的所有作者再多对多关系表中的关系记录,全部删除
book_obj.authors.clear()
return HttpResponse("ok")

ORM多表操作

ORM双下划线查询内置方法

Django ORM提供了一种方便的方式来进行高级查询,即使用双下划线(__)进行字段之间的关联和过滤。这些双下划线查询可以在查询中使用多个级别的关联模型,进行字段筛选、排序和其他操作。

双下划线查询方法 描述 示例
exact 进行精确匹配 Model.objects.filter(field__exact=value)
iexact 进行忽略大小写的精确匹配 Model.objects.filter(field__iexact=value)
contains 包含指定值 Model.objects.filter(field__contains=value)
icontains 包含指定值,忽略大小写 Model.objects.filter(field__icontains=value)
startswith 以指定值开头 Model.objects.filter(field__startswith=value)
istartswith 以指定值开头,忽略大小写 Model.objects.filter(field__istartswith=value)
endswith 以指定值结尾 Model.objects.filter(field__endswith=value)
iendswith 以指定值结尾,忽略大小写 Model.objects.filter(field__iendswith=value)
isnull 字段是否为空 Model.objects.filter(field__isnull=True)
in 匹配指定列表中的值 Model.objects.filter(field__in=[value1, value2])
gt 大于指定值 Model.objects.filter(field__gt=value)
gte 大于等于指定值 Model.objects.filter(field__gte=value)
lt 小于指定值 Model.objects.filter(field__lt=value)
lte 小于等于指定值 Model.objects.filter(field__lte=value)
range 在指定范围内 Model.objects.filter(field__range=(value1, value2))
year 获取日期字段的年份 Model.objects.filter(date_field__year=year)
month 获取日期字段的月份 Model.objects.filter(date_field__month=month)
day 获取日期字段的日期 Model.objects.filter(date_field__day=day)

一对一

表设计

将作者表中的ad字段关联到作者详情表中的id字段

| Author                 | AuthorDetail         |
|------------------------|----------------------|
| name | |
| age | |
| ad_id (FK) -------->| id (PK) |
| | birthday |
| | telephone |
| | address |

模型类

class Author(models.Model):
# id = models.AutoField(primary_key=True)
#其实模型类中id主键字段不需要我们手动指定,django的orm默认会给每张表
#添加一个id字段并且为主键,如果指定了主键,以指定主键的字段为主
name = models.CharField(max_length=32)
age = models.IntegerField()
#一对一关联字段
#ForeignKey参数,to:关联到哪张表,to_field:关联到表的哪个字段
#models.CASCADE 级联删除,表字段与表字段关联之后,删除字段数据之后与之关联的字段数据也会被删除。
ad = models.ForeignKey(to='AuthorDetail',
to_field='id',
on_delete=models.CASCADE
)

class AuthorDetail(models.Model):
birthday = models.DateField()
telphone = models.IntegerField(max_length=11)
address = models.CharField(max_length=64)

基于对象跨表查询-查询数据-正向查询

def OneByOne_get(request):
#正向查询,通过作者表中作者详细信息表id查询作者电话号码
user_obj = models.Author.objects.get(name="acai02")
#通过user_obj对象查找user_obj关联的作者详细信息表里面对应记录
user_obj.ad.telphone

return HttpResponse(user_obj.ad.telphone)

基于对象跨表查询-查询数据-反向查询

def OneByOne_get(request):
#反向查询,关联它的模型类名称小写,通过用户详细信息表中地址为甘肃的用户名称;然后通过返回的对象查询到作者的名称
user_detail_obj = models.AuthorDetail.objects.filter(address="甘肃").first()
user_detail_obj.author.name
return HttpResponse(user_detail_obj.author.name)

基于双下划线跨表查询-查询数据-正向查询

def OneByOneCheck(request):
#正向查询,查询作者家庭住址
res = models.Author.objects.filter(name="acai02").values("ad__address")
return HttpResponse(res)

基于双下划线跨表查询-查询数据-反向查询

def OneByOneCheck(request):
#反向查询,查询作者家庭住址
res = models.AuthorDetail.objects.filter(author__name="acai02").values("address")
return HttpResponse(res)

多对一

表设计

publish模型pub字段对应到book模型的id字段,表示一本书可以有多个出版社出版

| Publish                | Book                 |
|------------------------|----------------------|
| id (PK) | |
| name | |
| city | |
| | title |
| | pub_date |
| | price |
| pub_id (FK) ------->| id (PK) |

模型类

class Publish(models.Model):
"出版社表"
name = models.CharField(max_length=64)
city = models.CharField(max_length=32)

class Book(models.Model):
"书籍表"
title = models.CharField(max_length=64)
pub_date = models.DateField()
price = models.DecimalField(max_digits=10,decimal_places=2)
#pub字段和publish表关联,一对一关联
#ForeignKey这个类,生成数据库字段的时候,会自动将该属性名称_id作为我们的数据库字段名称
pub = models.ForeignKey(to='Publish')

基于对象跨表查询-查询数据-正向查询

def OneByMuti_get(request):
"""
一对多查询
:param request:
:return:
#正向查询,通过书籍表中书籍名称为少年阿宾的出版社
"""
book_obj = models.Book.objects.get(title="少年阿宾")
print(book_obj.pub.name)
return HttpResponse(book_obj.pub.name)

基于对象跨表查询-查询数据-反向查询

def OneByMuti_get(request):
#反向查询,查询甘肃教育出版社出版了那些书?book_set是在一对多关系中,Django ORM 自动生成的反向查询属性。
pub_obj = models.Publish.objects.get(name="甘肃教育出版社")
#book_set方法可能为多条记录,所以模型类名称小写_set
str_obj = pub_obj.book_set.all().values('title')
print(str_obj)
return HttpResponse(str_obj)

基于双下划线跨表查询-查询数据-正向查询

def OneByMutiCheck(request):
#正向操作,使用关联属性
res = models.Book.objects.filter(title="少年阿宾").values("pub__name")
print res
return HttpResponse(res)

基于双下划线跨表查询-查询数据-反向查询

def OneByMutiCheck(request):
"""
一对多,基于下划线查询
:param request:
:return:
"""
#反向操作,使用关联属性
res = models.Publish.objects.filter(book__title="少年阿宾").values("name")
print res
return HttpResponse(res)

多对多

表设计

书籍表中的pub字段和出版社id字段关联,书籍表中的作者字段和作者表中的id字段关联

| Book                  | Publish              |
|-----------------------|----------------------|
| id (PK) | |
| title | |
| pub_date | |
| price | |
| pub_id (FK) -------> | id (PK) |
| | |
| | |

| BookAuthors | Author |
|-----------------------|----------------------|
| id (PK) | |
| book_id (FK) -------->| id (PK) |
| author_id (FK) ------>| |

模型类

class Book(models.Model):
"书籍表"
#db_column='title'指定列名称
title = models.CharField(max_length=64, db_column='title')
pub_date = models.DateField()
price = models.DecimalField(max_digits=10,decimal_places=2)
#pub字段和publish表关联,一对一关联
#ForeignKey这个类,生成数据库字段的时候,会自动将该属性名称_id作为我们的数据库字段名称
pub = models.ForeignKey(to='Publish')

#authors在执行数据库同步指令之后,不会生成字段,会帮我们生成一个第三张表。
#这个表就是书籍表和作者表的多对多关联
#db_tables="xxx"定义第三张表的表名
authors = models.ManyToManyField("Author",db_tables="xxx")

基于对象跨表查询-查询数据-正向查询

def MutiByMuti_get(request):
#正向查询,阿才的博客这本书是谁写的
book_obj = models.Book.objects.get(title="少年阿宾")
print(book_obj.authors.all().values('name'))
return HttpResponse("ok")

基于对象跨表查询-查询数据-反向查询

def MutiByMuti_get(request):
"""
多对多查询
:param request:
:return:
"""
#反向查询,查询acai02写了哪些书
author_obj = models.Author.objects.get(name='acai02')
author_obj.book_set.all().values('title')
print(author_obj.book_set.all().values('title'))
return HttpResponse("ok")

基于双下划线跨表查询-查询数据-正向查询

def MutiByMutiCheck(request):
#正向查询,查询书籍是谁写的
res = models.Book.objects.filter(title="阿才的博客").values("authors__name")
return HttpResponse(res)

基于双下划线跨表查询-查询数据-反向查询

def MutiByMutiCheck(request):
#反向查询,查询书籍是谁写的
res = models.Author.objects.filter(book__title="阿才的博客").values("name")
print res
return HttpResponse(res)

聚合查询

什么是聚合查询

聚合查询是数据库中的一种查询操作,用于对数据进行汇总和统计。它可以对数据集进行计数、求和、平均值、最大值、最小值等统计操作,并返回结果作为查询的输出。

聚合查询的内置方法

方法 描述
Count() 计算指定字段的记录数。
Sum() 计算指定字段的总和。
Avg() 计算指定字段的平均值。
Max() 获取指定字段的最大值。
Min() 获取指定字段的最小值。

示例

from django.db.models import Count, Sum, Avg, Max, Min

# 统计书籍的数量
book_count = Book.objects.aggregate(book_count=Count('id'))

# 计算书籍价格的总和
total_price = Book.objects.aggregate(total_price=Sum('price'))

# 计算书籍价格的平均值
avg_price = Book.objects.aggregate(avg_price=Avg('price'))

# 获取书籍价格的最大值和最小值
price_range = Book.objects.aggregate(max_price=Max('price'), min_price=Min('price'))

分组查询

什么是分组查询

分组查询是一种在数据库中按照指定的字段进行分组,并对每个分组进行聚合操作的查询方式。它可以用于统计和分析数据,根据指定的条件对数据进行分类和聚合。

分组查询内置方法

方法 描述
values() 根据指定字段进行分组,返回每个分组的值以及聚合操作的结果。
annotate() 对每个分组进行聚合操作,并将结果添加到查询结果集中。
order_by() 对分组后的结果进行排序。
distinct() 去除重复的分组结果。
aggregate() 对每个分组进行聚合操作,并返回结果。
count() 统计每个分组中的记录数。
Sum() 计算每个分组中指定字段的总和。
Avg() 计算每个分组中指定字段的平均值。
Max() 获取每个分组中指定字段的最大值。
Min() 获取每个分组中指定字段的最小值。

示例

from django.db.models import Count, Sum, Avg, Max, Min

# 按照出版社分组,统计每个出版社出版的书籍数量
publishers = Book.objects.values('pub').annotate(book_count=Count('id'))

# 按照出版社分组,计算每个出版社的书籍价格总和和平均值
publishers_price = Book.objects.values('pub').annotate(total_price=Sum('price'), avg_price=Avg('price'))

# 按照出版日期年份分组,统计每年出版的书籍数量
publish_years = Book.objects.values('pub_date__year').annotate(book_count=Count('id'))

# 按照出版社分组,获取每个出版社的最贵和最便宜的书籍价格
publishers_price_range = Book.objects.values('pub').annotate(max_price=Max('price'), min_price=Min('price'))

F查询

什么是F查询

F查询是Django ORM中的一种查询技术,用于在查询中引用模型字段的值,实现字段之间的比较和运算。它可以在数据库层面进行计算和过滤,避免在Python代码中进行大量的循环和条件判断。

F查询内置方法

方法 描述
F() 引用模型字段的值,用于字段之间的比较和运算。
Expression() 创建更复杂的表达式,可以包含多个字段和运算符。
Q() 组合多个表达式,用于构建复杂的查询条件。
F()Q() 可以结合使用,实现更灵活的查询和过滤。

示例

from django.db.models import F, Q

# 查询价格大于库存的书籍
books = Book.objects.filter(price__gt=F('inventory'))

# 更新书籍价格为当前价格加上10
Book.objects.update(price=F('price')+10)

# 查询价格大于平均价格的书籍
average_price = Book.objects.aggregate(avg_price=Avg('price'))
books_above_average = Book.objects.filter(price__gt=average_price['avg_price'])

# 查询库存大于等于销量的书籍,并且出版社位于北京或上海
books = Book.objects.filter(inventory__gte=F('sales'), pub__city__in=['北京', '上海'])

# 使用Q对象进行复杂的查询,查询价格大于库存或库存小于等于10的书籍
books = Book.objects.filter(Q(price__gt=F('inventory')) | Q(inventory__lte=10))

Q查询

什么Q查询

Q查询是Django ORM中的一种查询技术,用于构建复杂的查询条件。它允许使用逻辑运算符(如AND、OR、NOT)和比较运算符(如等于、大于、小于等)来组合多个查询表达式,实现更灵活的查询操作。

Q查询内置方法

方法 描述
Q() 创建一个查询表达式,可以使用逻辑运算符和比较运算符组合多个条件。
~Q() 对查询表达式取反,用于排除满足条件的结果。
|(竖线) 对查询表达式进行逻辑或(OR)操作,返回满足任一条件的结果。
&(和号) 对查询表达式进行逻辑与(AND)操作,返回同时满足所有条件的结果。
complex_q_obj 可以通过组合多个查询表达式来构建更复杂的查询条件。

示例

from django.db.models import Q

# 查询价格大于100或库存小于20的书籍
books = Book.objects.filter(Q(price__gt=100) | Q(inventory__lt=20))

# 查询价格大于100且库存小于等于10的书籍
books = Book.objects.filter(Q(price__gt=100) & Q(inventory__lte=10))

# 查询价格小于50或库存大于100,并且不是甘肃教育出版社出版的书籍
books = Book.objects.filter(Q(price__lt=50) | Q(inventory__gt=100)).exclude(pub__name="甘肃教育出版社")

# 对查询条件取反,查询不是甘肃教育出版社出版且价格大于100的书籍
books = Book.objects.filter(~Q(pub__name="甘肃教育出版社") & Q(price__gt=100))

# 使用复杂的查询条件,查询价格大于平均价格或库存小于等于10的书籍
average_price = Book.objects.aggregate(avg_price=Avg('price'))
complex_q_obj = Q(price__gt=average_price['avg_price']) | Q(inventory__lte=10)
books = Book.objects.filter(complex_q_obj)

视图

什么是Django视图

Django视图(View)是一个Python函数或类,用于处理Web应用程序中的请求和生成响应。视图负责接收用户的请求,执行必要的处理逻辑,并返回一个响应给用户。
视图在Django中起着核心的作用,它处理了应用程序的业务逻辑和用户交互,并协调模型(Model)和模板(Template)之间的交互。
视图函数(Function-based views)是最常见的视图形式,它是一个Python函数,接收一个HttpRequest对象作为参数,并返回一个HttpResponse对象作为响应。

什么是request对象

在Django中,request对象是一个包含了用户HTTP请求信息的Python对象。它是视图函数或视图类的参数之一,在处理用户请求时被传递给视图函数或方法。
request对象封装了与用户请求相关的各种信息,包括请求的URL、HTTP方法、请求头部信息、请求参数、会话信息等。通过request对象,我们可以获取和操作这些信息,以便根据用户请求的内容进行相应的处理。

request对象的属性和方法

属性/方法 描述
request.body 请求的原始数据,作为字节字符串
request.GET 包含 GET 请求参数的字典对象
request.POST 包含 POST 请求参数的字典对象
request.COOKIES 包含请求中的所有 Cookie 的字典对象
request.FILES 包含上传文件的字典对象
request.META 包含请求的元数据(HTTP 头部信息)的字典对象
request.method 获取请求的方法,例如 GET、POST
request.path 请求的路径部分,不包括域名和参数
request.path_info 请求的路径信息,包括域名、路径和参数
request.get_host() 获取请求的主机名
request.get_port() 获取请求的端口号
request.get_full_path() 获取完整的请求路径,包括域名、路径和参数
request.is_secure() 判断请求是否使用安全连接(HTTPS)
request.is_ajax() 判断请求是否为 AJAX 请求
request.resolver_match 匹配请求的 URL 对应的 ResolverMatch 对象
request.content_type 请求的内容类型
request.session 请求的会话对象
request.user 当前登录用户的对象
request.get_full_path_info() 获取完整的请求路径信息,包括域名、路径和参数
request.is_ajax() 判断请求是否为 AJAX 请求
request.is_secure() 判断请求是否使用安全连接(HTTPS)
request.build_absolute_uri(location) 根据给定的路径构建完整的绝对 URI
request.get_signed_cookie(key, default=RAISE_ERROR, salt=’’, max_age=None) 获取已签名的 Cookie
request.set_signed_cookie(key, value, salt=’’, max_age=None, **kwargs) 设置已签名的 Cookie
request.get_host() 获取请求的主机名
request.get_port() 获取请求的端口号
request.is_secure() 判断请求是否使用安全连接(HTTPS)
request.get_full_path() 获取完整的请求路径,包括域名、路径和参数
request.get_full_path_info() 获取完整的请求路径信息,包括域名、路径和参数
request.build_absolute_uri(location) 根据给定的路径构建完整的绝对 URI
request.get_raw_uri() 获取请求的原始 URI

什么是response响应

在Web开发中,响应(Response)是服务器向客户端发送的数据,作为对客户端请求的回应。响应对象(Response Object)包含了服务器发送给客户端的内容,包括响应状态码、响应头部信息以及响应体(实际的内容)。它是客户端获取服务器返回的数据的接口。
在Django框架中,HttpResponse 是表示HTTP响应的对象。通过创建一个HttpResponse对象,你可以向客户端返回不同类型的响应,包括文本、HTML页面、JSON数据等。

response的特点

特点 描述
表示HTTP响应的对象 用于向客户端发送数据作为对请求的回应
可设置响应的内容、状态码、头部信息和Cookie 通过方法和属性进行设置
用于返回不同类型的响应 如文本、HTML页面、JSON数据等

response的方法和属性

方法/属性 描述
HttpResponse(content, content_type=None, status=None, reason=None) 创建一个HTTP响应对象,设置响应的内容、内容类型、状态码和状态原因
HttpResponse.content 获取响应的内容
HttpResponse.status_code 获取响应的状态码
HttpResponse.reason_phrase 获取响应的状态原因
HttpResponse.charset 获取响应的字符集
HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, samesite=None) 设置响应的Cookie
HttpResponse.delete_cookie(key, path='/', domain=None) 删除响应中的指定Cookie
HttpResponse.get(key, default=None) 获取响应头部信息中指定键的值
HttpResponse.set_header(key, value) 设置响应头部信息中的键值对

案例:返回html页面

from django.http import HttpResponse
import datetime

def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)

函数视图处理get请求

from django.shortcuts import render,HttpResponse
def my_view(request):
if request.method == 'GET':
return HttpResponse('OK')

类视图处理get请求

from django.shortcuts import render,HttpResponse
from django.views import View

class Cview(View):
def get(self,request):
return HttpResponse('COK')

函数视图装饰器

def wrapper(func):
def inner(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print("used_time:", end_time - start_time)

return res
return inner
@wrapper
def hello(request):
return HttpResponse("hello,world")

类视图装饰器

def wrapper(func):
def inner(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print("used_time:", end_time - start_time)

return res
return inner

class World(View):
@method_decorator(wrapper)
def get(self,request):
return HttpResponse('ok')

Cookie

什么是Cookie

Django cookie是在Django框架中使用的一种HTTP Cookie。HTTP Cookie是由Web服务器发送到Web浏览器的小型数据片段,用于在客户端存储和检索信息。Cookie通常用于跟踪用户会话、存储用户偏好设置、记录用户行为等。
在Django中,使用cookie模块来处理和操作Cookie。Django的cookie模块提供了一些便捷的方法和函数,使得操作Cookie变得简单。通过使用Django的HttpResponse对象的set_cookie()方法,可以设置Cookie的值、过期时间、域名、路径等属性。

Cookie的特点

以下是cookie的一些特点:

特点 描述
存储位置 Cookie保存在客户端的浏览器中,作为浏览器的一部分。
数据大小 Cookie的存储容量通常受到浏览器的限制,一般为几KB到几十KB。
数据传输 Cookie会在每次HTTP请求中自动发送到服务器,包括请求头中的Cookie字段。
过期时间 可以设置Cookie的过期时间,可以是会话级别的(关闭浏览器即失效)或具体的日期和时间。
安全性 Cookie是存储在客户端的,可以被用户修改和删除,因此不适合存储敏感信息。
跨域访问 Cookie默认只在设置它的域名和路径下有效,不支持跨域访问。
持久性 可以设置Cookie的持久性,使其在浏览器关闭后仍然有效。
作用范围 Cookie可以在整个网站的不同页面之间共享。
功能 Cookie通常用于会话管理、用户认证、记住用户偏好设置等。

Cookie的应用场景

应用场景 描述
会话管理 用于跟踪用户的会话状态,例如记录用户登录信息、验证用户身份等。
记住用户偏好设置 通过Cookie可以存储用户的偏好设置,例如语言偏好、主题选择、字体大小等。
购物车功能 通过Cookie可以在用户浏览网站时存储用户选择的商品信息,以实现购物车功能。
广告跟踪 用于追踪用户的浏览行为和兴趣,以提供个性化的广告推荐。
记住用户登录状态 通过设置一个持久性的Cookie,可以实现记住用户登录状态,避免用户每次访问都需要重新登录。
多域名共享数据 可以在多个域名之间共享数据,例如实现单点登录(SSO)功能。
防止恶意请求 可以使用Cookie来防止恶意请求,例如通过设置CSRF令牌(跨站请求伪造)来验证请求的合法性。

Cookie的内置方法

HttpRequest的Cookie相关属性和方法:

属性/方法 描述
request.COOKIES 包含请求中的所有Cookie的字典对象
request.COOKIES.get(key, default=None) 获取指定Cookie的值,如果不存在则返回默认值

HttpResponse的Cookie相关属性和方法:

属性/方法 描述
response.set_cookie(key, value=’’, max_age=None, expires=None, path=’/‘, domain=None, secure=False, httponly=False, samesite=None) 设置Cookie,将Cookie添加到响应对象中
response.delete_cookie(key, path=’/‘, domain=None) 删除指定的Cookie

示例:用户登录成功之后返回给客户端一个cookie

from django.http import HttpResponse

def login(request):
# 假设用户登录成功,获取用户信息
user_id = 123
username = 'example_user'

# 创建响应对象
response = HttpResponse('Login successful')

# 设置Cookie
response.set_cookie('user_id', user_id)
response.set_cookie('username', username)

return response

Session

什么是Session

Django的Session是一种在服务器端存储用户数据的机制。它基于Cookie或其他方式实现了跟踪和存储用户会话的功能。
在Django中,Session可以用来存储和检索与特定用户关联的数据,例如用户认证信息、用户偏好设置、购物车内容等。Session数据存储在服务器端,而客户端(通常是浏览器)只会在Cookie中保存一个用于标识会话的标识符。

Session的功能和特点

特点 功能
数据存储在服务器端 将用户数据存储在服务器端的持久化存储中,确保数据的安全性和可控性。
客户端标识符 为每个客户端分配一个唯一的标识符(session ID),通常以Cookie形式存储在客户端,用于标识和匹配会话。
客户端无法篡改 客户端只保存会话标识符,无法直接修改会话数据,只能通过与服务器的交互来操作数据。
可扩展性和配置性 提供灵活的配置选项,如存储后端选择、过期时间设置、加密和签名等,可以根据需求进行自定义设置。
多种存储方式 可以选择不同的存储后端,如数据库、缓存等,根据应用程序的需求和规模进行选择。
跨请求保持状态 通过会话数据,可以在不同的请求之间共享和保持状态,实现用户认证、权限管理、购物车等功能。
灵活的数据访问 提供方便的API和方法,可以轻松地存储、读取和修改会话数据。
会话管理和过期处理 可以设置会话的过期时间,并提供过期处理机制,如自动清理过期会话数据。
与用户认证集成 可以与Django的用户认证系统集成,实现用户登录和身份验证功能。

Session的使用场景

使用场景 描述
用户认证和身份管理 Session可以用于存储和验证用户的身份信息,实现用户认证和登录功能。
用户个性化设置 可以使用Session存储用户的个性化设置,如主题选择、语言偏好、布局偏好等。
购物车功能 在电子商务应用中,可以使用Session来存储和管理用户的购物车信息。
记住登录状态 使用Session可以实现”记住我”的功能,让用户在下次访问时保持登录状态。
权限管理 可以使用Session来存储用户的权限信息,根据权限来控制用户对特定资源的访问。
表单数据暂存 在多步骤的表单流程中,可以使用Session暂存用户填写的表单数据,以便在下一步继续使用。
会话跟踪和分析 Session可以用于跟踪用户的会话信息,记录用户的访问记录和行为分析。
应用状态管理 可以使用Session来存储应用程序的状态信息,如在线用户数、系统配置等。
多设备同步 使用Session可以实现用户在多个设备上的会话同步,保持一致的登录状态和数据状态。

示例:当用户登录成功后,可以使用Session来记录用户的登录状态并在后续请求中进行验证

在Django中,request对象是每个视图函数的参数,用于接收客户端发送的请求数据。对于同一个用户的请求,request对象在整个请求-响应周期内是保持不变的,因此可以在不同的视图函数之间传递数据。
在上述示例中,request对象可以在login函数和dashboard函数之间传递数据。在login函数中,当用户登录成功后,将用户名存入Session中:request.session[‘username’] = username。然后在dashboard函数中,可以通过request.session[‘username’]来获取之前存入Session的用户名。
这样,登录成功后,username信息就可以在不同的视图函数中传递和使用。但是需要注意的是,Session数据是存储在服务器端的,因此在不同的请求之间共享数据时,需要确保使用相同的Session对象(例如,使用相同的Session中间件)来访问Session数据。

from django.shortcuts import render, redirect

def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')

# 假设验证用户名和密码的逻辑代码

# 验证成功,将用户信息存入Session
request.session['username'] = username
return redirect('/dashboard') # 重定向到用户仪表盘页面

return render(request, 'login.html')

def dashboard(request):
# 检查用户是否已登录
if 'username' in request.session:
username = request.session['username']
return render(request, 'dashboard.html', {'username': username})
else:
return redirect('/login') # 用户未登录,重定向到登录页面

Cookie和Session的区别

Cookie和Session都是用于在Web应用中跟踪和管理用户状态的机制,但在具体的使用场景和实现方式上有一些区别。
Cookie是在客户端存储的小型文本文件,用于在不同的HTTP请求之间传递数据,通常用于实现用户身份验证、记住登录状态等功能。
Session是一种服务器端的机制,用于存储和管理用户会话数据,可以在不同的请求之间保持状态,并且提供了更高的数据安全性和灵活性。在实际应用中,根据需求和安全性要求,可以选择使用Cookie、Session或两者结合来管理用户状态和传递数据。

特点 Cookie Session
数据存储位置 客户端 服务器端
存储容量 通常4KB左右 通常无明确限制,但受服务器配置和资源影响
生命周期 可设置过期时间,可以是临时的或长期的 通常与用户会话相关,关闭浏览器后自动删除
数据安全性 数据在客户端存储,可以被修改或窃取 数据存储在服务器端,相对较安全
存储内容 可以存储任意字符串数据 可以存储任意数据类型,包括对象、列表等
访问方式 可以通过浏览器开发工具查看和修改 只能通过服务器端进行访问和操作

中间件

什么是Django中间件

在 Django 中,中间件是一种插入到请求/响应处理过程中的组件,它可以在处理请求之前和之后执行一些操作。中间件提供了一种方便的方式来修改 Django 的请求和响应对象,以及在处理请求的各个阶段执行额外的逻辑。

中间件使用场景

使用场景 描述
认证和授权 中间件可以用于验证用户的身份,检查用户是否具有足够的权限来访问特定的视图或资源。
请求/响应处理 中间件可以在请求到达视图之前或响应发送给客户端之前,对请求和响应进行处理。例如,可以对请求进行预处理,如解析请求参数、检查 CSRF 令牌等。对于响应,可以进行后处理,如添加额外的响应头、压缩响应内容等。
缓存和性能优化 中间件可以用于缓存请求的响应,以减少数据库或其他资源的访问次数,提高性能。
异常处理 中间件可以捕获视图中发生的异常,并根据需要执行适当的操作,如记录错误、发送通知等。
日志记录 中间件可以用于记录请求的详细信息,如请求的路径、处理时间等,以便后续分析和排查问题。
请求/响应转换 中间件可以修改请求或响应的内容,例如对请求进行重定向、对响应进行内容转换等。

Django中间件的作用

用来对请求和响应做一些统一加工和处理的,比如对所有请求中的post请求做一个csrf token认证,使用了django.middleware.csrf.CsrfViewMiddleware中间件,后面视图中能够使用request.session做一个session操作,这个request.session的功能就是在这个中间件django.contrib.sessions.middleware.SessionMiddleware中加工好的。

Django请求生命周期


1.浏览器访问/index/路径,将用户的http请求发送给wsgi封装的socket
2.wsgi将用户http请求发送给中间件,按顺序执行每个中间件的process_request方法
3.中间件执行完成之后交给url控制器,将用户访问url路径解析成相应视图函数
4.视图函数通过数据库模型、template模板渲染,将数据返回给中间件
5.中间件按倒序执行每个中间件的response方法
6.中间件将数据返回给wsgi,由wsgi按http协议封装成响应的数据返回给浏览器

自定义中间件

自定义中间件的流程:
1.在app文件夹下创建一个文件夹,比如:custommiddleware
2.在custommiddleware文件夹下创建py文件,比如:middlewares
3.在middlewares.py文件中写如下内容

#只有response_request方法函数返回None表示该函数的流程是正常的。
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect

class LoginAuth(MiddlewareMixin):
def process_request(self,request):
#设置登陆白名单,浏览器访问/login不走login auth认证
while_list = ['/login',]
print(request.path)
#判断浏览器访问路径如果不是/login则执行下面的流程
if not request.path in while_list:
print("测试中间件")
#只有response_request方法函数返回None表示该函数的流程是正常的。
print("session: %s" %request.session.get('is_login'))
if request.session.get('is_login'):
return None
else:
return redirect('login')

在settings.py配置文件中引入中间件

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'app01.custommiddleware.middlewares',
]

中间件常用的五个方法

方法 描述
process_request(self, request) 在每个请求到达中间件时调用,对请求进行预处理。
process_view(self, request, view_func, view_args, view_kwargs) 在视图函数被调用之前调用,可以对视图进行处理。
process_exception(self, request, exception) 在视图函数抛出异常时调用,可以捕获并处理异常。
process_response(self, request, response) 在响应发送给客户端之前调用,对响应进行后处理。
process_template_response(self, request, response) 在响应是模板响应对象时调用,对模板响应进行处理。

process_request中间件方法

1.如果有两个中间件,其中一个中间件process_request返回的是None,那么才会继续执行后面的中间件的process_request方法;
2.如果最后一个中间件返回None,那么逻辑才会继续执行到url路由控制器;
3.如果process_request里面return的是一个HttpResponse对象,那么后面的中间件的process_request将不再执行,也不会走到url控制器。

process_response中间件方法

注意:
1.自定义的中间件如果定义了process_response中间件方法,必须要return response
2.如果有两个中间件md1、md2,如果md1中间件process_request返回的是HttpResponse,那么中间件md2的process_request和process_response方法都不会执行,直接把md1的process_response返回。

def process_response(self,request,response):
'''
:param request: 当前请求对象
:param response: 视图函数响应对象
:return:
'''
#响应头部信息添加或修改数据
response['xx'] = 'yy'
return response

process_views中间件方法

process_views执行顺序:
1.当一个请求到达 Django 时,它会经过 process_request 方法的处理,然后进入 URL 路由系统,确定要调用的视图函数。在调用视图函数之前,会依次执行每个中间件的 process_view 方法。
2.如果在中间件的 process_view 方法中返回了一个响应对象,那么后续的中间件的 process_view 方法以及视图函数本身将不会被执行,请求将直接返回该响应对象。
3.如果所有中间件的 process_view 方法都执行完毕,且没有返回响应对象,那么 Django 将继续调用确定的视图函数来处理请求。在视图函数执行完毕后,会按照相反的顺序依次执行中间件的 process_response 方法。

使用案例:

def process_view(self,request,view_func,view_args,view_kwargs):
'''

:param request: 当前请求对象
:param view_func: 此次请求要执行的视图函数对象
:param view_args: 视图函数的参数
:param view_kwargs: 视图函数的参数
:return:
'''
print(view_func.__name__)

process_exception中间件方法

执行顺序:
1.当一个视图函数抛出异常时,Django 会依次调用每个中间件的 process_exception 方法,直到其中一个中间件处理了该异常并返回一个响应对象,或者所有中间件的 process_exception 方法都执行完毕。
2.如果一个中间件的 process_exception 方法返回了一个响应对象,那么后续的中间件的 process_exception 方法将不会被执行,请求将直接返回该响应对象。
3.如果所有中间件的 process_exception 方法都执行完毕且没有返回响应对象,Django 将继续处理该异常,默认行为是将异常传递给 Django 的异常处理机制。

def process_exception(self,request,exception):
'''
当视图函数触发异常时,执行该方法
:param request: 请求对象
:param exception: 异常捕获
:return:
'''

process_template_response中间件方

执行顺序:
1.当一个视图函数返回一个模板响应对象时,Django 会依次调用每个中间件的 process_template_response 方法。
2.在 process_template_response 方法中,中间件可以对模板响应进行处理,例如添加模板变量、修改模板上下文等。
3.如果一个中间件的 process_template_response 方法返回了一个响应对象,那么后续的中间件的 process_template_response 方法将不会被执行,请求将直接返回该响应对象。
4.如果所有中间件的 process_template_response 方法都执行完毕且没有返回响应对象,Django 将继续发送模板响应给客户端。

def process_template_response(self,request,response):
'''
视图函数定义一个render方法,会触发该方法
:param request:
:param response:
:return:
'''

用户认证和授权

什么是用户的认证和授权

  1. 用户认证指的是验证用户的身份,确保用户是合法的、已注册的用户。Django 提供了内置的身份验证系统,它可以处理用户的注册、登录、注销等功能。通过用户认证,应用程序可以验证用户提供的凭据(如用户名和密码),并识别用户身份。
  2. 用户授权是指确定用户是否具有足够的权限来执行特定的操作或访问特定的资源。Django 提供了基于角色和权限的授权系统。在授权系统中,可以定义用户角色和分配相应的权限,然后根据用户的角色和权限,决定其是否具有执行某个操作或访问某个资源的权限。

用户认证和授权的功能

功能 描述
用户模型 (User Model) 内置的用户模型,用于存储用户的身份信息,如用户名、密码等。可以通过扩展用户模型来添加自定义的用户属性。
身份验证后端 (Authentication Backends) 处理用户的认证过程,包括验证用户凭据、检查用户状态等。可以选择合适的身份验证后端来满足应用程序的需求。
登录视图 (Login View) 内置的登录视图,显示登录表单、验证用户凭据并进行身份验证。可自定义登录视图以适应应用程序的需求。
注销视图 (Logout View) 内置的注销视图,用于注销当前用户并清除用户的会话信息。
装饰器和权限验证 (Decorators and Permissions) 通过装饰器和权限验证限制对某些视图或资源的访问。只有具有适当权限的用户才能执行相应的操作。
用户组和权限 (User Groups and Permissions) 管理用户组和权限,用户组是一组用户的集合,可以为用户组分配权限。通过分配用户到用户组,可以方便地管理用户的权限。

实现认证授权的步骤

  1. 定义用户模型:使用 Django 的内置用户模型 (django.contrib.auth.models.User) 或扩展它来定义自定义用户模型。用户模型用于存储用户的身份信息。
  2. 配置认证后端:在 Django 的配置文件 (settings.py) 中配置认证后端 (AUTHENTICATION_BACKENDS),选择适合你应用程序需求的后端。例如,使用 Django 的内置后端 (django.contrib.auth.backends.ModelBackend) 来验证用户的凭据。
  3. 创建登录视图:定义登录视图,用于显示登录表单并处理用户提交的登录凭据。你可以使用 Django 的内置登录视图 (django.contrib.auth.views.LoginView) 或自定义视图来处理登录逻辑。
  4. 创建注销视图:定义注销视图,用于注销当前用户并清除用户的会话信息。你可以使用 Django 的内置注销视图 (django.contrib.auth.views.LogoutView) 或自定义视图来处理注销逻辑。
  5. 保护视图和资源:通过装饰器或权限验证来限制对某些视图或资源的访问。使用 @login_required 装饰器来要求用户登录才能访问某个视图。使用 @permission_required 装饰器来要求用户具有特定权限才能访问某个视图。
  6. 定义用户组和权限:使用 Django 的用户组和权限管理功能来组织用户并分配权限。可以创建用户组,将用户添加到组中,并为组分配适当的权限。通过授权用户组,可以更方便地管理用户的权限。
  7. 使用 Django 表单和模板标签:Django 提供了与用户认证和授权相关的表单和模板标签,如登录表单 (AuthenticationForm)、用户信息表单 (UserCreationFormUserChangeForm)、用户认证模板标签 ({% if user.is_authenticated %}) 等。可以使用这些工具来简化用户认证和授权的开发。

示例

普通用户:文章增删改查权限
管理员用户:文章、用户增删改查权限

1.定义用户模型:

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
# 添加自定义字段或属性
pass

2.创建文章模型:

from django.db import models
from your_app.models import CustomUser

class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
# 添加其他文章字段

def __str__(self):
return self.title

3.创建视图和表单:

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, permission_required
from your_app.models import Article
from your_app.forms import ArticleForm

@login_required
def article_list(request):
articles = Article.objects.all()
return render(request, 'article_list.html', {'articles': articles})

@login_required
@permission_required('your_app.add_article', raise_exception=True)
def create_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save(commit=False)
article.author = request.user
article.save()
return redirect('article_list')
else:
form = ArticleForm()
return render(request, 'create_article.html', {'form': form})

@login_required
@permission_required('your_app.change_article', raise_exception=True)
def edit_article(request, article_id):
article = get_object_or_404(Article, pk=article_id)
if request.method == 'POST':
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
form.save()
return redirect('article_list')
else:
form = ArticleForm(instance=article)
return render(request, 'edit_article.html', {'form': form, 'article': article})

@login_required
@permission_required('your_app.delete_article', raise_exception=True)
def delete_article(request, article_id):
article = get_object_or_404(Article, pk=article_id)
article.delete()
return redirect('article_list')

4.配置 URL 路由:

from django.urls import path
from your_app.views import article_list, create_article, edit_article, delete_article

urlpatterns = [
# ...
path('articles/', article_list, name='article_list'),
path('articles/create/', create_article, name='create_article'),
path('articles/edit/<int:article_id>/', edit_article, name='edit_article'),
path('articles/delete/<int:article_id>/', delete_article, name='delete_article'),
# ...
]

5.创建文章表单:

from django import forms
from your_app.models import Article

class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'content']

6.定义权限:
在 Django 的权限系统中,为普通用户和管理员用户分配相应的权限。

  • 普通用户权限:
    • your_app.view_article: 查看文章
    • your_app.add_article: 添加文章
    • your_app.change_article: 修改文章
    • your_app.delete_article: 删除文章
  • 管理员用户权限:
    • your_app.view_article: 查看文章
    • your_app.add_article: 添加文章
文章作者: 慕容峻才
文章链接: https://www.acaiblog.top/django教程/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿才的博客
微信打赏
支付宝打赏