表单
HTTP 请求
HTTP 协议以“请求-回复”的方式工作,客户端发送请求时,可以在请求中附加数据,服务器通过解析请求获得客户端传来的数据,并根据 URL 来提供特定的服务。
GET 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from django.http import HttpResponse from django.shortcuts import render
def search_form(request): return render(request, 'search_form.html')
def search(request): request.encoding='utf-8' if 'query' in request.GET and request.GET['query']: message = '你搜索的内容为: ' + request.GET['query'] else: message = '你提交了空表单' return HttpResponse(message)
from django.conf.urls import url from . import search
urlpatterns = [ url(r'^search-form/$', search.search_form), url(r'^search/$', search.search), ]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Demo-Search</title> </head> <body> <form action="/search/" method="get"> <input type="text" name="query" /> <input type="submit" value="搜索" /> </form> </body> </html>
|
POST 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from django.views.decorators import csrf from django.shortcuts import render
def search_post(request): ctx = {} if request.POST: ctx['rlt'] = request.POST['post_text'] return render(request, "post_result.html", ctx)
from django.conf.urls import url from . import views,testdb,search,search2
urlpatterns = [ url(r'^search-post/$', search_post.search_post), ]
|
Request 对象
每个视图函数的第一个参数是一个 HttpRequest 对象
1 2 3 4
| from django.http import HttpResponse
def demo(request): return HttpResponse("Hello world")
|
属性
- path: 请求页面的全路径,不包括域名,例如:”/index/“
- method: 请求使用的 HTTP 方法,常用值包括:GET, POST
- encoding: 表单数据使用的编码,只有当请求的内容类型是
application/x-www-form-urlencoded
时才使用
- GET: 包含所有 HTTP GET 参数的类字典对象
- POST: 包含所有 HTTP POST 参数的类字典对象
- REQUEST: 是 GET 和 POST 的合体,但是有特殊性,先查找 POST 属性,然后再查找 GET 属性
- FILES: 包含所有上传文件的类字典对象(注:只有在请求方法是 POST,并且请求页面中
- COOKIES: 包含所有 cookie 的标准 Python 字典对象,Keys 和 Values 都是字符串
- META: 包含所有 HTTP 头部信息的类字典对象
- CONTENT_LENGTH
- CONTENT_TYPE
- QUERY_STRING: 未解析的原始查询字符串
- REMOTE_ADDR: 客户端 IP 地址
- REMOTE_HOST: 客户端主机名
- SERVER_NAME: 服务器主机名
- SERVER_PORT: 服务器端口
- HTTP_USER_AGENT: 客户端代理信息
- HTTP_REFERER: Referring URL
- HTTP_ACCEPT_ENCODING
- HTTP_ACCEPT_LANGUAGE
- HTTP_HOST: 客户发送的 HTTP 主机头信息
- HTTP_X_BENDER: X-Bender 头信息
- user: 是一个 django.contrib.auth.models.User 对象,代表当前登录的用户,如果当前访问的用户没有登录,则 user 将被初始化为 django.contrib.auth.models.AnonymousUser 的实例,只有激活 Django 的 AuthenticationMiddleware 时才会生效。
- user.is_authenticated(): 如果是已认证的用户(即用户已登录),返回 True;否则返回 False
- user.is_staff(): 如果是超级用户,返回 True;否则返回 False
- user.is_active(): 如果是已激活的用户,返回 True;否则返回 False
- user.is_anonymous(): 如果是匿名用户,返回 True;否则返回 False
- user.get_username(): 返回用户名
- user_id: 当前登录用户的主键,int 类型
- session: 当前会话的 SessionStore 对象,唯一可读写的属性,只有激活 Django 中的 session 支持时才可用。
- raw_post_data: 原始 HTTP POST 数据,为解析过,是一个字符串。
方法
- getitem(key): 返回 GET 或 POST 的键值,先取 POST 后取 GET,如果没有则抛出 KeyError 异常
- has_key(): 检查 request.GET or request.POST 中是否包含参数指定的 Key
- get_full_path(): 返回包含查询字符串的完整路径
- is_secure(): 检查请求是否使用 HTTPS 协议,如果安全则返回 True
- is_ajax(): 判断请求是否是通过 XMLHttpRequest 发起的
- get_host(): 返回请求的主机部分
- get_port(): 返回请求使用的端口
- get_scheme(): 返回请求使用的协议,例如 http, https
- build_absolute_uri(location): 返回 location 参数在当前请求下完整的绝对路径
QueryDict 对象
在 HttpRequest 对象中,GET 和 POST 属性是 django.http.QueryDict 类型的实例。
其类似字典的自定义类,用来处理单键对应多值的情况,实现所有的标准字典方法,还有一些特有方法。
方法
- getitem: 和标准字典的不完全相同,如果 Key 对应多个 Value,则其返回最后一个 Value
- setitem: 设置 Key 和 Value,如果 Key 已经存在,则对应的 Value 会被替换,只能在一个 mutable QueryDict 对象上被调用,就是通过 copy()产生的一个 QUeryDict 对象的拷贝
- get(): 如果 Key 对应多个 Value,则返回最后一个
- update(): 参数可以是 QueryDict,也可以是标准字典,和标准字典的 update 方法不同,其会保留 Key 对应的所有 Value,即添加 items 而不是替换。
1 2 3 4 5 6 7 8 9 10 11 12 13
| >>> q = QueryDict('a=1')
>>> q = q.copy()
>>> q.update({'a': '2'})
>>> q.getlist('a')
['1', '2']
>>> q['a']
['2']
|
- items(): 该方法使用单值逻辑的getitem方法,返回一个二元元组列表,每个二元元组包含(key, value)
1 2 3 4 5
| >>> q = QueryDict('a=1&a=2&a=3')
>>> q.items()
[('a', '3')]
|
- values():
- copy(): 返回对象的拷贝,底层实现使用的标准库的 copy.deepcopy()方法,是 mutable,可以更改该拷贝的值
- getlist(key): 返回和参数 Key 对应的所有值,作为一个 Python List 返回,如果 Key 不存在,则返回空列表
- setlist(key, list**): 设置 Key 的值为 list**
- setlistdefault(key, list): 和 setdefautl 不同,其接收 list 而不是单个 value 作为参数
- appendlist(key, value): 添加 item 和 key 关联到内部的 list
- lists(): 和 items()类似,但会返回 key 的所有值,作为一个 list
1 2 3 4 5
| >>> q = QueryDict('a=1&a=2&a=3')
>>> q.lists()
[('a', ['1', '2', '3'])]
|
- urlencode(): 返回一个字符串,表示对 QueryDict 中所有 Key 和 Value 的 URL 编码
视图
视图函数
视图函数是一个简单的 Python 函数,它接受 Web 请求并返回 Web 响应。
视图函数接收一个 HttpRequest 对象作为第一个参数,HttpRequest 对象包含了请求的元数据,比如请求方法、请求路径、请求头等。
视图函数返回一个 HttpResponse 对象,HttpResponse 对象可以包含以下内容:
一般放在项目的 views.py 文件中,类似于 MVC 中的控制器。
请求对象:HttpRequest
- GET
- 数据类型是 QueryDict
- 包含 HTTP GET 请求的所有参数
- 有相同的键,就将所有的值放到对应的列表里
- 取值格式: 对象.方法
- get(): 返回字符串,如果该键对应有多个值,取出该键的最后一个值
1 2 3
| def demo_get(request): name = request.GET.get("name") return HttpResponse('姓名:{}'.format(name))
|
- POST
- 数据类型是 QueryDict
- 包含 HTTP POST 请求的所有参数
- 常用于 form 表单,form 表单里的标签 name 属性对应参数的键,value 属性对应参数里的值
- 取值格式: 对象.方法
- get(): 返回字符串,如果该键对应有多个值,取出该键的最后一个值
1 2 3
| def demo_post(request): name = request.POST.get("name") return HttpResponse('姓名:{}'.format(name))
|
- body
- 数据类型是二进制字节流,是原生请求体里的参数内容
- 在 HTTP 中用于 POST,因为 GET 没有请求体
- 在 HTTP 中不常用,而在处理非 HTTP 形式的报文时非常有用,如:二进制图片、XML、JSON 等
1 2 3 4
| def demo_body(request): name = request.body print(name) return HttpResponse("测试:body")
|
- path
- 获取 URL 中的路径部分,数据类型是字符串
1 2 3 4
| def demo_path(request): name = request.path print(name) return HttpResponse("测试:path")
|
- method
- 获取当前请求的方式,数据类型是字符串,且结果为大写
1 2 3 4
| def demo_method(request): name = request.method print(name) return HttpResponse("测试:method")
|
响应对象:HttpResponse
- HttpResponse()
- 返回文本,参数为字符串,若含有 html 标签,也可以渲染
1 2 3
| def demo_res(request): return HttpResponse("<a href='https://www.baidu.com/'>百度一下</a>")
|
- render()
- 返回文本,第一个参数 request,第二个参数为字符串(页面名称),第三个参数为字典(可选参数,向页面传递的参数:键为页面的参数名,值为 views 的参数名)
1 2 3
| def demo_render(request): name ="测试: render" return render(request,"index.html",{"name":name})
|
- redirect()
- 重定向,跳转新页面,参数为字符串,字符串填写页面路径
- 一般用于 form 表单提交后,跳转到新页面
1 2
| def demo_redirect(request): return redirect("/index/")
|
- render 和 redirect 均是在 HttpResponse 的基础上封装的,底层返回的也是 HttpResponse 的对象
路由
- 根据用户的请求链接来判断对应的处理函数,并返回处理结果,即将 URL 和视图建立映射关系
- 在 Django 中,URL 的配置文件是 urls.py,每一条配置对应相应的处理方法
1 2 3 4 5 6 7 8 9 10
| from django.urls import re_path
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), re_path(r'^articles/([0-9]{4})/$', views.articles), ]
|
正则路径的分组
无名分组
- 按位置传参,一一对应
- views 中除了 request,其它形参的数量要与 urls 中的分组数量一致
1 2 3 4 5 6 7 8 9 10 11 12 13
| urlpatterns = [ path('admin/', admin.site.urls), re_path("^index/([0-9]{4})/$", views.index), ]
from django.shortcuts import HttpResponse
def index(request, year): print(year) return HttpResponse('测试')
|
有名分组
- 语法:(?P<组名>正则表达式)
- 按关键字传参,与位置顺序无关
- views 中除了 request,其它形参的数量要与 urls 中的分组数量一致,并且 views 中的形参名称要与 urls 中的组名一致
1 2 3 4 5 6 7 8 9 10 11 12
| urlpatterns = [ path('admin/', admin.site.urls), re_path("^index/(?P<year>[0-9]{4})/$", views.index), ]
from django.shortcuts import HttpResponse def index(request, year, month): print(year,month) return HttpResponse('测试')
|
路由分发(include)
Django 项目里多个 app 共用一个urls.py
容易造成混乱,也不方便维护。
可以将每个 app 的 urls.py 拆分出来,在主 urls.py 中使用 include 进行导入
- 在每个 app 里都创建一个 urls.py
- 在项目名称目录下的 urls.py 文件里,统一将路径分发给各个 app 目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from django.contrib import admin from django.urls import path,include
urlpatterns = [ path('admin/', admin.site.urls), path("app01/", include("app01.urls")), path("app02/", include("app02.urls")), ]
from django.urls import path,re_path from app01 import views urlpatterns = [ re_path(r'^login/(?P<m>[0-9]{2})/$', views.index, ), ]
from django.urls import path,re_path from app02 import views urlpatterns = [ re_path("^xxx/(?P[0-9]{4})/$", views.xxx), ]
|
反向解析
- 当路由层 url 发生改变,在视图层和模板层动态反向解析出更改后的 url,免去修改的操作
- 一般用在模板中的超链接及视图中的重定向
普通路径
- 在 urls.py 中给路由起别名,name=”路由别名”
- 在 views.py 中,利用 reverse(“路由别名”)反向解析
- 在模板中的 html 文件内,利用
{% url "路由别名" %}
反向解析
1 2 3 4 5 6 7 8
| path("login1/", views.login, name="login")
return redirect(reverse("login"))
<form action="{% url 'login' %}" method="post">
|
正则路径(无名分组)
- 在 urls.py 中给路由起别名,name=”路由别名”
- 在 views.py 中,利用 reverse(“路由别名”, args=(1, 符合正则匹配的参数))反向解析
- 在模板中的 html 文件内,利用
{% url "路由别名" 符合正则匹配的参数 %}
反向解析
1 2 3 4 5 6 7 8
| re_path(r"^login/([0-9]{2})/$", views.login, name="login")
return redirect(reverse("login",args=(10,)))
<form action="{% url 'login' 10 %}" method="post">
|
正则路径(有名分组)
- 在 urls.py 中给路由起别名,name=”路由别名”
- 在 views.py 中,利用 reverse(“路由别名”, kwargs={“分组名”:符合正则匹配的参数})反向解析
- 在模板中的 html 文件内,利用
{% url "路由别名" 分组名=符合正则匹配的参数 %}
反向解析
1 2 3 4 5 6 7 8
| re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")
return redirect(reverse("login",kwargs={"year":2333}))
<form action="{% url 'login' year=2333 %}" method="post">
|
命名空间
- 是用于表示标识符的可见范围
- 一个标识符可以在多个命名空间中定义,它在不同命名空间中的含义是互不相干的
- 一个新的命名空间中可以定义任何标识符,不会与任何重复的标识符发生冲突,因为重复的定义都处理其它命名空间中
- 路由别名 name 没有作用域,反向解析时会在项目全局顺序搜索,当搜索到第一条匹配时立即返回,如果不同 app 目录下存在相同的路由别名时,会导致 URL 反向解析错误。
普通路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| include(("app名称:urls","app名称"))
path("app01/", include(("app01.urls","app01"))) path("app02/", include(("app02.urls","app02")))
path("login/", views.login, name="login")
return redirect(reverse("app01:login")
<form action="{% url 'app01:login' %}" method="post">
|