系统环境
python版本
django版本
安装好了python版本用Pycharm创建时,指定了python版本会自动下载相应的django版本
django的MTV
Django的MTV框架模式
- Model 模型
- Template 模板
- Views 视图
手动安装Django
pip install django
pip install django==4.2.4
django命令
输入python manage.py会看到所有的django命令
指令文档:https://docs.djangoproject.com/zh-hans/5.1/ref/django-admin/
Django指令有31条,每条指令说明如下表格所示:
指令 | 说明 |
---|---|
changepassword | 修改内置用户表的用户密码 |
createsuperuser | 为内置用户表创建超级管理员帐号 |
remove_stale_contenttypes | 删除数据库中已经不使用的数据局表 |
check | 检测整个项目是否存在异常 |
compilemessages | 编译语言文件,用于项目的区域语言设置 |
createcachetable | 创建缓存数据表,为内置的缓存机制提供存储功能 |
dbshell | 进入Django配置的数据库,可以执行数据库的SQl语句 |
diffsettings | 显示当前settings.py的配置信息与默认配置的差异 |
dumpdata | 导出数据表的数据并以JSON格式存储,如python manage.py dump data index>data.json,这是index的模型所对应的数据导出,并保存在data.json文件中 |
flush | 清空数据表的数据信息 |
inspectdb | 获取项目所有模型的定义过程 |
loaddata | 将数据文件导入数据表,如python manage.py loaddata data.json |
makemessages | 创建语言文件,用于项目的区域语言设置 |
makemigrations | 从模型对象创建数据迁移文件并保存在App的migrations文件夹中 |
migrate | 根据迁移文件的内容,在数据里生成相应的数据表 |
optimizemigration | 优化迁移操作并覆盖现有的迁移文件 |
sendtestemail | 抽指定的收件人发送测试的电子邮件 |
shell | 进入Django的Shell模式,用于调试项目功能 |
showmigrations | 查看当前项目的所有迁移文件 |
sqlflush | 查看清空数据库的SQL语句脚本 |
sqlmigrate | 根据迁移文件内容输出相应的SQL语句 |
sqlsequencereset | 重置数据表递增字段 的索引 值 |
squashmigrations | 对迁移文件进行压缩处理 |
startapp | 创建项目应用App |
startproject | 创建新的Django项目 |
test | 运行App里面的测试程序 |
testserver | 新建测试数据库,并使用该数据库运行项目 |
clearsessions | 清除会话(Session)数据 |
collectstatic | 收集所有的静态文件 |
findstatic | 查找静态文件的路径信息 |
runserver | 在本地计算机上启动Django项目 |
命令创建项目
python manage.py startproject 项目名
#如果创建到当前文件夹项目名后面加个.
python manage.py startproject .
命令创建App
# 创建到根目录下的app
python manage.py startapp App名
#如果创建到指定目录下,如在apps下生成index App.需要先建立apps/index文件夹在执行以下命令
python manage.py startapp index apps/index
常用配置
注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 注册app
'account.apps.AccountConfig'
]
中文显示
# 中文显示
LANGUAGE_CODE = 'zh-hans'
# 时区上海
TIME_ZONE = 'Asia/Shanghai'
# 设置中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# 添加中间件: LocaleMiddleware django内置功能中文显示
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
数据库配置
django提供了5种数据库引擎
- django.db.backends.sqlite3
- django.db.backends.mysql
- django.db.backends.oracle
- django.db.backends.postgresql
- django.db.backends.postgresql_psycopg2
sqlite3
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
mysql
使用mysql需要安装连接模块
pip install mysqlclient #安装时需要本地安装了mysql
django对mysqlclient版本有使用有要求,可以在django的源码查看mysqlclient版本要求
pip install pymysql
在项目的__init__.py
中增加以下代码
import pymysql
pymysql.install_as_MySQLdb()
两者选择其一,不建议同时使用
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
'NAME': 'blog', # 数据库名称
'USER': 'root', # MySQL 用户
'PASSWORD': '123456', # MySQL 密码
'HOST': 'localhost', # 数据库服务器地址,远程则改为 IP 地址
'PORT': '3306', # MySQL 端口,默认 3306
'OPTIONS': {
'charset': 'utf8mb4', # 推荐使用 utf8mb4 支持 Emoji
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", # 避免非严格模式带来的数据问题
},
}
}
如果使用MySQL的版本是8.0以上,会提示django.utils.OperationaError错误信息,因为MySQL8.0以上的加密方式发生了改变,用户密码彩的是CHA2(caching_sha2_password)加密方式
解决报错用管理员登录mysql执行以下代码:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'newpassword';
FLUSH PRIVILEGES;
多个数据库连接
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'MyIndex': {
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
'NAME': 'my_index', # 数据库名称
'USER': 'root', # MySQL 用户
'PASSWORD': '123456', # MySQL 密码
'HOST': 'localhost', # 数据库服务器地址,远程则改为 IP 地址
'PORT': '3306', # MySQL 端口,默认 3306
'OPTIONS': {
'charset': 'utf8mb4', # 推荐使用 utf8mb4 支持 Emoji
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", # 避免非严格模式带来的数据问题
},
},
'mysqlbak': {
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
'NAME': 'mysqlbak', # 数据库名称
'USER': 'root', # MySQL 用户
'PASSWORD': '123456', # MySQL 密码
'HOST': 'localhost', # 数据库服务器地址,远程则改为 IP 地址
'PORT': '3306', # MySQL 端口,默认 3306
'OPTIONS': {
'charset': 'utf8mb4', # 推荐使用 utf8mb4 支持 Emoji
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", # 避免非严格模式带来的数据问题
},
}
}
若项目中连接了多个数据库,每个模型所对应的数据表可以选择在某个数据库中生成,如果 没有模型没有指向某个数据库,则模型就会在key为default的数据库中生成.
配置文件
在项目根目录新建my.cnf
文件增加以下配置
# my.cnf
[client]
database=index
user=root
password=root123456
host=127.0.0.1
port=3306
编写配置文件my.cnf必须设置[clinet]分组,settings.py配置DATABASE配置信息如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
'OPTIONS':{'read_default_file':str(BASE_DIR/'my.cnf')},
},
}
执行生成数据表(配置不能有中文)
python manage.py migrate
查看数据表
更改index的view.py
from django.shortcuts import render
from django.contrib.contenttypes.models import ContentType
def home(request):
c=ContentType.objects.values_list().all()
print(c)
return render(request, 'home.html')
静态和媒体文件
资源路由
在“DEBUG=True`时,STATIC_URL,默认创建项目就有配置,可以旋转css,js,images等静态资源,注册了的app下的static下的文件可以访问
STATIC_URL = 'static/'
以上配置在根目录访问static中的文件是访问不了,如果注册的app换了一个名称也是不能识别的,用到STATICFILES_DIRS
资源整合
STATICFILES_DIRS就是处理多个静态文件目录的
# 静态文件
STATIC_URL = 'static/' # 静态文件的路由地址
STATICFILES_DIRS = [
BASE_DIR / "static", # 配置项目的static,就是项目根目录的static
# BASE_DIR / "article/static",
]
配置app下的其它目录
STATIC_URL = 'static/' # 静态文件的路由地址
STATICFILES_DIRS = [
BASE_DIR / "static", # 配置项目的static,就是项目根目录的static
BASE_DIR / "index/Mystatic", # 配置index App下的Mystatic为静态文件目录
]
当访问static可以访问根目录的static,也可以访问注册app下的static,还可以访问注册app的Mystatic下的文件
如果改了STATIC_URL = 'allStatic/'
,访问的地址就是这个目录
STATIC_URL = 'allStatic/' # 静态文件的路由地址
STATICFILES_DIRS = [
BASE_DIR / "static", # 配置项目的static,就是项目根目录的static
BASE_DIR / "index/Mystatic", # 配置index App下的Mystatic为静态文件目录
]
资源部署
STATIC_ROOT,是在服务器上部署项目时,收集整个项目的静态资源并存放在一个新的文件夹中,以实现服务器和项目之间的映射关系.配置如下:
STATIC_ROOT = BASE_DIR / 'AllStatic'
设置STATIC_ROOT需要使用Django操作指令python manage.py collectstatic来收集所有静态资源到配置文件夹中
可以设置服务器的一个绝对路径,需要有写入权限
媒体文件
一般情况下,STATIC_URL用于设置静态文件的路由地址,如css,js以及常用图片等.
对于经常变动的资源,如用户上传的头像,歌曲文件等,通常存放在媒体资源文件夹中.
设置如下:
# 媒体文件路由地址
MEDIA_URL = '/media/'
# 获取media文件夹的完整路径信息
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
设置完成属性后,还需要将media文件夹注册到Django中.以便让Django知道如何找到媒体文件,否则无法在浏览器中访问该文件夹内的文件信息.
打开项目文件中的urls.py,为媒体文件夹media添加相应的路由地址.
from django.contrib import admin
from django.urls import path, re_path
# 配置媒体文件夹media路由地址
from django.views.static import serve
from django.conf import settings
# 方法一
urlpatterns = [
path('admin/', admin.site.urls),
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media')
]
# 方法二
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'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',
# 将media_url上传文件路径注册到横版中
'django.template.context_processors.media'
],
},
},
]
配置完成后重启服务,访问media下的文件,可以正常访问
模板配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 注册根目录和index下的templates文件夹
'DIRS': [
BASE_DIR / 'templates',
BASE_DIR / 'index/templates',
],
'APP_DIRS': True, # 是否在app中查找模板
'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',
# 将media_url上传文件路径注册到横版中
'django.template.context_processors.media'
],
},
},
]
测试设置是否成功
在根目录的templates下新建404.html和500.html处理服务器错误和404页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>404页面</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>500页面</h1>
</body>
</html>
在app index的templates下新建home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>home页面</h1>
</body>
</html>
在index的views设置处理路由函数
from django.shortcuts import render
def home(request):
return render(request, 'home.html')
def custom_404_view(request):
return render(request, '404.html')
def custom_500_view(request):
return render(request, '500.html')
设置路由
from django.contrib import admin
from django.urls import path, re_path
from index import views
# 配置媒体文件夹media路由地址
from django.views.static import serve
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home), # 首页
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media')
]
settings.py
DEBUG = False
ALLOWED_HOSTS = ['*']
首页路由设计一个错误
from django.shortcuts import render
def home(request):
# 测试服务器500
print(fsfsd)
return render(request, 'home.html')
全部都可以访问
中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# 添加中间件: LocaleMiddleware django内置功能中文显示,国际化和本地化功能
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
每个中间件的设置顺序是固定的,如果 随意变更中间件,容易导致异常,说明如下:
SecurityMiddleware: 内置的安全机制,用于保护用户与网络的通信安全
SessionMiddleware: 会话功能
LocaleMiddleware:国际化和本地化功能
CommonMiddleware:处理请求信息,规范化请求崆
CsrfViewMiddleware:开启CSRF防护功能
AuthenticationMiddleware:开启内置的用户认证系统
MessageMiddleware:开启内置的信息提示功能
XFrameOptionsMiddleware:防止恶意程序单击劫持
用户模型
AUTH_USER_MODEL = 'user.UserInfo'
路由系统
路由定义
路由地址就是我们常说的网址,而视图函数(或者视图类)则是在App的views.py文件中定义的函数(或类)
路由的变量的类型有字符串类型、整型、lug和uuid,最为常用的是字符串类型和整型。
路由列表 由urlpatterns 变量表示,每个列表元素代表一条路由。一个列表由三部分组成 :
- 第一个参数路由地址
- 第二个参数路由所对应的处理函数(视图函数或视图类)
- 第三个参数为路由之外的参数,参数为字典类型
类型说是如下:
- 字符串类型:匹配任何非空字符串,但不含斜杠。如果没有指定类型,默认使用该类型。
- 整型:匹配0和正整数
- Slug:可理解为注释,后缀或附属等该概念,常作为路由的解释性字符。可以匹配任何ASSII 字符以及连接符和下画线,能使路由更加清晰易懂。
- UUID:匹配一个 uuid 格式的对象。为了防止冲突,规定必须使用“-”,并且怕有字母必须小写。
在路由中,使用变量符号”<>“可以为路由设置变量。括号里面的内容以冒号划分为两部分,冒号前面代表的是变量的数据类型,冒号后面代表的是变量名,变量名可自行命名。
正则表达式路由
路由的正则表达示是路由函数 re_path 定义的,作用是对路由地址进行截取与判断。正则表达示以圆括号为单位,每个圆括号的前后可以使用斜杠或者其它字符来分隔或结束。
变量以一个圆括号为单位以(?P
- ?P 是固定格式,字母 P 必须为大写。
为变量名 - [0-9]{4}是正则表达式的匹配模式,代表变量长度为4,只允许0-9的值。
命名空间与路由命名
命名空间
路由分发的时候可以指定命名空间
路由函数 include 设有参数 arg 和 namespace,参数 arg 指向项目应用 App 的 urls.py 文件,其数据格式以元组或字符串表示,可选参数 namespace 是路由的命名空间。
要对路由设置参数 namespace,则参数arg 必须以元组格式表示,并且元组的长度必须为2.元组的元素说明如下:
- 第一个元素为项目应用的 urls.py 文件
- 第二个元素可以自行命名,但不能为空。通常情况下,会将其命名为项目应用 app的名称,如(‘index.urls’,‘index’)
如果设置了参数 namespace,并且参数 arg为字符串或元组长度不足2,则运行 djadngo 项目会报以下错误
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
正确的配置如下:
from django.contrib import admin
from django.urls import path, re_path, include
from index import views
# 配置媒体文件夹media路由地址
from django.views.static import serve
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(('index.urls', 'index'), namespace='index')), # 正确配置
path('user/', include(('user.urls','user'), namespace='user')), # 正确配置
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media')
]
路由命名
指定路由处理的视图函数或视图类时可以指定路由的地址 name如下:
from django.urls import re_path, path
from . import views
urlpatterns = [
path('', views.profile, name='userProfile'),
path('login/', views.login, name='userLogin'),
path('register/', views.register, name='userRegister'),
]
反射解析
Django 反射解析主要由函数 reverse 和 resolve 实现:
- 函数reverse 是通过路由命名或可调用视图对象来生成路由地址
- 函数 resolve 是通过路由地址来获取路由对象信息的
from django.shortcuts import render, reverse
from django.urls import resolve
def home(request):
result = reverse('user:userRegister')
res = resolve(result)
print(result)
print(res)
return render(request, 'home.html')
访问首页返回
/user/register/
ResolverMatch(func=user.views.register, args=(), kwargs={}, url_name='userRegister', app_names=['user'], namespaces=['user'], route='user/register/')
reverse
源码
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
if urlconf is None:
urlconf = get_urlconf()
resolver = get_resolver(urlconf)
args = args or []
kwargs = kwargs or {}
prefix = get_script_prefix()
if not isinstance(viewname, str):
view = viewname
else:
*path, view = viewname.split(":")
.....
函数 reverse 中设必选参数viewname,其余参数是可选参数,参数说明如下:
- viewname:代表路由命名或可调用视图对象,一般情况下是以路由命名 name 来生成路由地址
- urlconf:设置反向解析的 URLconf 模块。默认情况下,使用配置文件 settings.py的 ROOT_URLCONF属性
- args:以列表方式传递路由地址变量,列表元素顺序和数量应与路由地址变量的顺序和数量一致
- kwargs:以字典方式传递路由地址变量,字典 的键必须对应路由地址变量名,字典键值对数量 与变量的数量要一致
- current_app:提示当前正在执行的视图所在的项目应用,主要起到提示作用,在功能上并无实质的作用
一般情况下中需高雷函数 reverse 的参数 viewname 即可,如果路由地址设有变量,可自行设置参数 args 或 kwargs 来设置路由的变量值。但是 args 和 kwargs 不能同时设置,否则会提示 ValueError报错信息。
from django.urls import re_path, path
from . import views
urlpatterns = [
path('', views.profile, name='userProfile'),
path('login/', views.login, name='userLogin'),
path('register/<str:a>', views.register, name='userRegister'),
]
from django.shortcuts import render, reverse
from django.urls import resolve
def home(request):
result = reverse('user:userRegister',args=['a'])
res = resolve(result)
print(result) # /user/register/a
print(res)
return render(request, 'home.html')
同时设置报错
from django.shortcuts import render, reverse
from django.urls import resolve
def home(request):
b=1
result = reverse('user:userRegister',args=['a'],kwargs={'b':b})
res = resolve(result)
print(result)
print(res)
return render(request, 'home.html')
resolve
源码
def resolve(path, urlconf=None):
if urlconf is None:
urlconf = get_urlconf()
return get_resolver(urlconf).resolve(path)
函数 resolve 设有两个参数,path 是必选参数 ,urlfconf 是可选参数,参数说明如下:
- path:代表路由地址,通过路由地址来获取对应的路由对象信息。
- urlconf:设置反向解析的 URLconf模块。在默认情况下,使用配置 settings.py 的 ROOT_URLCONF属性
- 返回值如下:
ResolverMatch(func=user.views.register, args=(), kwargs={}, url_name='userRegister', app_names=['user'], namespaces=['user'], route='user/register/')
路由重定向
Django 的网页重定向有两种方式:
- 路由重定向,使用 Django 内置的 RedirectView 实现,默认支持 HTTP 的 GET 请求
- 自定义视图的重定向,在自定义视图的响应状态设置重定向
路由重定向
from django.views.generic import RedirectView
urlpatterns = [
path('', views.home, name='home'),
path('turnTo/', RedirectView.as_view(url='/'), name='turnTo'),
]
视图重定向
- HttpResponseRedirect 状态码301,永久性跳转
- HttpResponsePermanentRedirect 状态码302,临时的跳转,搜索引擎认为新的网址只是暂时的
- 函数redirect
HttpResponseRedirect和HttpResponsePermanentRedirect的使用只需传入路由地址即可,不支持路由命名的传入,所以有了函数 redirect
源码
def redirect(to, *args, permanent=False, **kwargs):
redirect_class = (
HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
)
return redirect_class(resolve_url(to, *args, **kwargs))
def resolve_url(to, *args, **kwargs):
# If it's a model, use get_absolute_url()
if hasattr(to, "get_absolute_url"):
return to.get_absolute_url()
if isinstance(to, Promise):
# Expand the lazy instance, as it can cause issues when it is passed
# further to some Python functions like urlparse.
to = str(to)
# Handle relative URLs
if isinstance(to, str) and to.startswith(("./", "../")):
return to
# Next try a reverse URL resolution.
try:
return reverse(to, args=args, kwargs=kwargs)
except NoReverseMatch:
# If this is a callable, re-raise.
if callable(to):
raise
# If this doesn't "feel" like a URL, re-raise.
if "/" not in to and "." not in to:
raise
# Finally, fall back and assume it's a URL
return to
from django.shortcuts import render, reverse,redirect
def home(request):
return redirect(reverse('user:userLogin'))
FBV视图
网站运行遵循 HTTP 协议,核心交互由 HTTP 请求和 HTTP 响应组成。
响应方式
HTTP响应方式也被称为 HTTP 状态码
- 第一种:消息状态码、成功状态码、重定向状态码、请求错误状态码、服务器错误码五种
- 第二种:成功状态码、重定向状态码、异常响应状态码(客户端请求错误和服务器错误)三种。
返回响应内容
视图函数通过 return 方式返回响应内容,设置不同的响应方式,则需要使用Django 内置的响应类,如下表:
响应类型 | 说 明 |
---|---|
HttpResponse(‘hello world’) | 状态码200,请已成功被服务器接收 |
JsonResponse({‘foo’:‘bar}) | 状态码200, 响应内容为 JSON 数据 |
StreamingHttpResponse() | 状态码200, 响应内容以流式输出 |
HttpResponseRedirect(’/‘) | 状态码302,重定向首页 |
HttpResponsePermanentRedirect(’/‘) | 状态码301,永久重定向重定向首页 |
HttpResponseBadRedirect(‘400’) | 状态码400,访问的页面不存在或请求错误 |
HttpResponseNotRedirect(‘404’) | 状态码404,访问的页面不存在或网页的URL 失效 |
HttpResponseForbidden(‘403’) | 状态码403,没有访问权限 |
HttpResponseNotAllowed(‘405’) | 状态码405,不允许使用该请求方式 |
HttpResponseServerErrord(‘500’) | 状态码500,服务器内容错误 |
以上响应类主要来自模块Django.http
打开源码发现响应类都是在 HttpResponse 的基础上实现的,只不过他们的HTTP状态码有所不同。
render
因为HttpResponse的使用过程要生成网页内容,就需要将 HTML 语言以字符串的形式表示,如果网页过大,就会增加视图函数的代码量,同时也没有体现模板的作用,因为 Django 在此基础上进行了封装处理,定义了函数 render 和 redirect。部分源码如下:
def render(
request, template_name, context=None, content_type=None, status=None, using=None
):
"""
Return an HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
def redirect(to, *args, permanent=False, **kwargs):
"""
Return an HttpResponseRedirect to the appropriate URL for the arguments
passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urls.reverse()` will be used
to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location.
Issues a temporary redirect by default; pass permanent=True to issue a
permanent redirect.
"""
redirect_class = (
HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
)
return redirect_class(resolve_url(to, *args, **kwargs))
render 的 request 和 template_name 参数是必选参数,其余的是可选参数,各参数说明如下:
- request:浏览器向服务器发送的请求对象,包含用户信息、请求内容和请求方式等
- templaet_name:模板文件名,用于生成网页内容
- context:对模板上下文赋值中,以字典格式表示,默认情况下是一个空字典
- content_type:响应内容的数据格式,一般情况下使用默认值即可
- status:HTTP 状态码,默认为200
- using:设置模板引擎,用于解析模板文件,生成网页内容
异常响应
异常响应是指 HTTP 状态码为404或500的响应状态,它与正常的响应过程是一样的,只是 HTTP 状态码有所不同。使用 render 函数作为响应过程,设置参数status 状态码为404或500即可实现异常响应
def home(request):
return render(request, 'home.html', status=404)
def home(request):
return render(request, 'home.html', status=500)
全局设置异常响应页面
urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(('index.urls', 'index'), namespace='index')),
]
handler404 = 'index.views.page_not_found'
handler500 = 'index.views.page_not_error'
views.py
from django.shortcuts import render
from django.http import Http404
def home(request):
if request.GET.get('error',''):
raise Http404('没有找到页面')
return render(request, 'home.html')
def page_not_found(request,exception):
return render(request, '404.html', status=404)
def page_not_error(request):
return render(request, '500.html', status=500)
文件下载
Django 提供了三种方式来实现下载功能,分别是 HttpResponse、StreamingHttpResponse 和 FileResponse
- HttpResponse 是所有响应过程的核心类,它的底层功能是 HttpResponseBase
- StreamingHttpResponse是在HttpResponseBase 基础上进行继承和重写的,实现流式响应输出,适用于大规模数据响应和文件传输响应
- FileResponse 是在 StreamingHttpResponse 的基础上进行继承和重写,实现文件的流式响应输出,只适用于文件传输响应
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('download/file1', views.download1, name='download1'),
path('download/file2', views.download2, name='download2'),
path('download/file3', views.download3, name='download3'),
]
views.py
from django.http import Http404, HttpResponse, StreamingHttpResponse, FileResponse
def home(request):
return render(request, 'home.html')
def download1(request):
file_path = '/Users/rh/Pictures/10.jpg'
try:
r = HttpResponse(open(file_path, 'rb'))
r['content_type'] = 'application/octet-stream'
r['Conntent-Disposition'] = 'attachment;filename=10.jpg'
return r
except Exception:
raise Http404('下载错误')
def download2(request):
file_path = '/Users/rh/Pictures/9.jpg'
try:
r = StreamingHttpResponse(open(file_path, 'rb'))
r['content_type'] = 'application/octet-stream'
r['Conntent-Disposition'] = 'attachment;filename=9.jpg'
return r
except Exception:
raise Http404('下载错误')
def download3(request):
file_path = '/Users/rh/Pictures/8.jpg'
try:
f = open(file_path, 'rb')
r = FileResponse(f, as_attachment=True, filename='7.jpg')
return r
except Exception:
raise Http404('下载错误')
以上三个都能实现下载,前两个都是以流的方式返回,第三个可以直接下载文件:
- HttpResponse实现文件下载存在很大的弊端,其工作原理是将文件读取并载入内存,然后输出到浏览器上实现下载功能。如果下载的文件较大,会占用很多内存,下载大文件 Django 推荐使用StreamingHttpResponse和FileResponse,这两个方法将下载文件分批写入服务器的本地磁盘,而不将文件载入服务器的内存。
- StreamingHttpResponse和FileResponse实现原理是一样的,都是把文件分批写入服务器的本地磁盘,实现文件的流式响应输出
- 从适用范围来说,StreamingHttpResponse适用范围更为广泛,可支持大规模数据或文件输出,而FileResponse只支持文件输出
- 从适用方式来说,StreamingHttpResponse支持数据格式或文件输出,因此在使用时需要设置响应输出类型和方式,而FileResponse只需要设置3个参数即可实现文件下载功能。
HTTP请求对象
WSGIRequest 的源码
class WSGIRequest(HttpRequest):
def __init__(self, environ):
script_name = get_script_name(environ)
# If PATH_INFO is empty (e.g. accessing the SCRIPT_NAME URL without a
# trailing slash), operate as if '/' was requested.
path_info = get_path_info(environ) or "/"
self.environ = environ
self.path_info = path_info
# be careful to only replace the first slash in the path because of
# http://test/something and http://test//something being different as
# stated in RFC 3986.
self.path = "%s/%s" % (script_name.rstrip("/"), path_info.replace("/", "", 1))
self.META = environ
self.META["PATH_INFO"] = path_info
self.META["SCRIPT_NAME"] = script_name
self.method = environ["REQUEST_METHOD"].upper()
# Set content_type, content_params, and encoding.
self._set_content_type_params(environ)
try:
content_length = int(environ.get("CONTENT_LENGTH"))
except (ValueError, TypeError):
content_length = 0
self._stream = LimitedStream(self.environ["wsgi.input"], content_length)
self._read_started = False
self.resolver_match = None
def _get_scheme(self):
return self.environ.get("wsgi.url_scheme")
从类 WSGIRequest 的定义中可以看到,它继承并重写类 HttpRequest,若要获取 请求信息,只需从类 WSGIRequest 中读取相关的属性即可,常用的属性说明:
- COOKIE:
- FILES:
- GET:
- POST:
- META:
- method:
- Path:
- Seesion:
- user