django处理请求流程
django简单说明
1.安装
- pip install django
2.创建项目
- 目录结构
├── demo #项⽬⽬录
│ ├── __init__.py #包标志
│ ├── settings.py #项⽬配置⽂件
│ ├── urls.py #路由映射表
│ └── wsgi.py #wsgi接⼝
└── manage.py #项⽬管理命令
- manage.py:是Django⽤于管理本项⽬的命令⾏⼯具,之后进⾏站点运⾏,数据库⾃动⽣成等都是通过本⽂件完成。
- python manage.py startapp app 创建自己的应用
- 把app加入settings.py中的INSTALLED_APPS中
- python manage.py runserver启动服务
- 访问127.0.0.1:8000
3.settings文件
# 项目根目录
BASE_DIR = Path(__file__).resolve().parent.parent
# 调试模式
DEBUG = True
# 允许访问的主机
ALLOWED_HOSTS = ['*']
# 安装的app,自己创建的app也应该加入
INSTALLED_APPS
# 模板配置
TEMPLATES
# 数据库配置,支持sqlite、mysql、oracle、pg
DATABASE=
#语⾔编码
LANGUAGE_CODE = 'zh-hans'
#时区
TIME_ZONE = 'Asia/Shanghai'
简单视图
- app应用下的views.py代表视图,接受用户请求,经过处理逻辑后返回客户端文本、html、重定向等
from django.http import HttpResponse
def index(request):
return HttpResponse("index view")
简单路由
- 定义视图后,还需要把请求路径匹配到视图,在app应用目录下创建urls.py文件
from django.urls import path
from .views import index
urlpatterns = [
path('index/', index, name="index"),
]
- urlpatterns是固定名称,不应该改动
- path函数第一个参数是路径名,第二个是视图函数,name参数可以完成名称到路径的映射。
- 即使添加urls.py中的配置,依然不能访问,需要把app下的urls.py导入到项目目录下urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('app.urls'))
]
- 通过api路径前缀就可以访问到app应用下的urls
- 注意api前不要加/
- 访问http://127.0.0.1:8000/api/index/ 就可以看到自己写的视图
简单的模板
- 目标:返回一个页面
- 在templates下面创建index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h2>this is index page</h2>
</body>
</html>
- 修改views.py文件
from django.shortcuts import render
def index(request):
return render(request, "index.html")
- request参数是必要的,由框架把请求封装成request对象然后传参
简单模型
- 在models.py文件中定义模型类,一个模型类相当于一张表
class User(models.Model):
uname = models.CharField(max_length=20)
password = models.CharField(max_length=32)
-
执行python manage.py migrate
-
执行python manage.py makemigrations
-
执行python manage.py migrate
-
说明:第一次执行python manage.py migrate,生成django框架需要的表,python manage.py makemigrations生成数据库迁移文件,记录生成自定义表的信息,后续修改,都会生成迁移文件,第二次python manage.py migrate,就是真正生成自定义的数据库
-
创建2条数据
- 创建视图
def users(request):
users = User.objects.all()
return render(request, "users.html", context={"users", users})
- 添加路由
path('users/', users, name="users")
- 访问127.0.0.1:8000/api/users
路由
path函数参数
- 路径名称
- 视图函数
- kwargs可选参数
- 名称:通过该名称反向查询路径名称
1.路径名称
- 除了具体的路径名称,还可以写正则表达式严格要求请求路径
re_path('re/(\d{11})', re_view, name="re")
- 假设上面路径匹配手机号
def re_view(request, phone):
return HttpResponse(phone)
- 视图中添加处理函数
- 总结:
-
urls.py中路径匹配是从上往下匹配
-
一个视图可以有多个请求路径
-
路径前面不要加/
-
如果路径匹配不上会报404错误,把settings.py中DEBUG=False,会调用默认错误视图处理
-
动态url
path("hello/<name>/",views.hello)
path("show/<name>/<int:age>",views.show)
- 当使用<>包起来变量,那么视图函数必须使用一样的变量名
def foo(request, name):
pass
- int:age和上面一样,但是也定义了该变量的类型是int
- 参数类型
- str:不定义时默认就是str类型
- int:匹配0和正整数
- slug:匹配数字字母、-、_组成的字符串
- path:匹配非空字符串
path/<path: path>:假设有这么一个路径名称,当请求127:0.0.1:8000/path/etc/a/b/c,会传递etc/a/b/c字符串给视图
re_path(r'^hello/(\w+)/(\d{1,2})/$',views.hello)
re_path(r'^hello/(?P<name>\w+)/(?P<age>\d{1,2})/$',views.hello),
- ()部分是正则的组,当匹配成功时,会把内容传递给视图函数
- re_path(r'^hello/(\w+)/(\d{1,2})/$',views.hello)中(\w+)是位置参数,视图函数中任意变量名都可以接受
def foo(request, value1, value2):
pass
- re_path(r'^hello/(?P<name>\w+)/(?P<age>\d{1,2})/$',views.hello):视图函数只能是name和age
def foo(request, name, age):
pass
请求和响应对象
1.HttpRequest对象
- 服务器接收请求后封装成的对象
- 试图函数的第一个对象必须是HttpRequest对象
- HttpRequest可以获取的信息
| 属性 | 说明 |
|---|---|
| content-type | 请求的mime类型 |
| GET | 一个QUeryDict对象,包含get请求方式的所有参数,也就是?后的内容 |
| POST | 一个QUeryDict对象,包含post方式的所有参数 |
| COOKIES | 一个标准的python字典,包含所有的cookie |
| SESSION | 一个类似字典的对象,表示当前会话,只有django启用会话时才可用 |
| PATH | 一个字符串,表示请求的完整路径,不包括域名 |
| method | 一个字符串,表示http常用的方法,GET、POST |
| FILES | 一个QueryDict,包含所有的上传文件 |
| META | 请求头信息 |
| scheme | 协议 |
- META中常用的键值
| 键 | 说明 |
|---|---|
| HTTP_REFERER | 来源页面 |
| REMOTE_ADDR | 客户端ip |
| REMOTE_HOST | 客户端主机 |
- 常用方法
| 方法名 | 说明 |
|---|---|
| get_host() | 主机+端口 |
| get_full_path() | 获取请求路径+查询字符串 |
| is_ajax() | ajax请求返回True |
| build_absolute_uri() | 完整url |
QueryDict
-
QueryDict是Dict的⼦类,和Dict最⼤的不同是,值都是列表。⽤于存储从请求中传递过来的参数,例如对于表单中select、checkbox等多值参数,QueryDict⾮常合适。get、post、files请求都对应⼀个QueryDict
-
HttpRequest中QueryDict是不可变的,只能获取值,不能修改
-
QueryDict键值对都是字符串
-
QueryDict中⼀个键可以对应多个值
-
示例
{'hobby':['打篮球','玩游戏','k歌'],'name':['tom'],'age':'21'}
- 实战
urlpatterns = [
path('req_test/', req_test, name="req_test"),
]
- 定义视图函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<h2>name {{ name }}</h2>
<h2>hobby {{ hobbies }}</h2>
<h2>host {{ host }}</h2>
<h2>full_path {{ full_path }}</h2>
<h2>absolute_uri {{ absolute_uri }}</h2>
<h2>remote_address {{ remote_address }}</h2>
<h2>REMOTE_HOST {{ REMOTE_HOST }}</h2>
<h2>remote_address {{ scheme }}</h2>
</body>
</html>
2.HttpResponse对象
- 每一个试图函数必须返回一个响应对象
| 属性 | 说明 |
|---|---|
| content | 字符串 |
| charset | 字符编码 |
| status_code | 状态码 |
| content_type | 指定输出的MIME类型 |
示例
-
- 不用模板
def hello(req):
return HttpResponse("hello world")
def goodbye(req):
res = HttpResponse()
res.content = b'good bye'
res.charset = "utf-8"
res.content_type = 'text/html'
return res
- 2.使用模板
def studentlist(req):
for key in req.GET.lists():
print(key)
allstudent = Student.objects.all()
return render(req,'studentlist.html',context={'data':allstudent})
- 3.常用方法
write(content) 设置内容 == obj.content
set_cookie() 设置cookie
delete_cookie() 删除cookie
3.JsonResponse对象
-
JsonResponse 是HttpResponse的⼦类,⽤于向客户端返回json数据。⼀般⽤于ajax请求。它的content-type缺省值为:application/json
-
class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True,json_dumps_params=None, **kwargs)
data:可以是字典,如果safe设置为False,也可以是json序列化对象
encoder:编码格式,缺省是django.core.serializers.json.DjangoJSONEncoder
safe:缺省是True,如果传递⾮字典给data,则报TypeError
- 示例
from django.http import JsonResponse
import json as myJson
#返回json数据
def json(req):
jsonStr = JsonResponse({'name':'zhangsan','age':18})
jsonStr = myJson.dumps({'name':'zhangsan','age':18})
return HttpResponse(jsonStr)
- json.dumps给ajax返回数据以后 js代码中需要将json数据使⽤Json.parse() 进⾏解析成js对象 ⽽JsonResponse会⾃动转换为js对象(少了异步Json.parse()的转换)
def courselist(req):
courses = Course.objects.all() #QuerySet
data = {'course':list(courses.values())} #查询结果集QuerySet转字典
return JsonResponse(data) #传字典给JsonResponse
def courselist(req):
courses = Course.objects.all()
data = json.dumps(list(courses.values())) #查询结果集QuerySet转
Json字符串,序列化
return JsonResponse(data,safe=False) #safe必须设置为False
重定向
- 不带参数重定向
#urls.py
urlpatterns = [
path('',views.index),
re_path(r'^list/$',views.list_user),
#redirect 重定向路由地址
url(r'^redirect/$',views.Redirect)
]
#views.py
def index(req):
return render(req,'index.html')
def list_user():
return HttpResponse("list user")
def Redirect(req):
# return redirect('http://localhost:9000/')
# return redirect('/')
return redirect("list/")
- 带参数重定向
#urls.py
urlpatterns = [
path('repath/<int:num>/', views.repath),
re_path(r'^parameter/(?P<num1>\d+)/(?P<num2>\d+)/$',views.parameter),
]
#views.py
def repath(req,num):
return redirect("parameter/3/5")
def index(request):
return HttpResponse("⾸⻚")
def parameter(req,num1, num2):
return HttpResponse("num1={},num2={}".format(num1,num2))
- 反向解析
- 根据namespace和name查找真是路径,urls.py中app_name指定namespace,path函数中name=指定name
# urls.py中
app_name = 'App' # namespace 命名空间
urlpatterns = [
path('', views.index, name="index"),
path('para/<int:num1>/<int:num2>/', "para"),
]
#python代码中写法
def repath(req):
#res = reverse("App:index")
# print(res,type(res))
#return redirect(res)
# path中参数或re_path中的位置参数,args可以是列表或元组
# return redirect(reverse("App:para",args=(1,2)))
# re_path中命名组,带关键字参数
return redirect(reverse("App:para",kwargs={'num1':1,'num2':3}))
# 模板中的写法:
<h2><a href="/form/">展示表单</a></h2>
<h2><a href="/index/">死链接⽆参的跳转</a></h2>
<h2><a href="/args/1/2/">死链接带参的跳转</a></h2>
<h2><a href="{% url 'App:index' %}">动态⽣成路由地址不带参的跳转</a>
</h2>
<h2><a href="{% url 'App:args1' 1 2 %}">动态⽣成路由地址带参的跳转</a>
</h2>
<h2><a href="{% url 'App:args1' num1=1 num2=2 %}">re_path中命名组,动
态⽣成路由地址带关键字参数的跳转</a></h2>
默认错误视图
- 需要在settings中把DEBUG=False
- 在templates目录下创建错误试图
- 示例