视图层 view

视图层是 Django 处理请求的核心代码层,我们大多数 Python 代码都集中在这一层面。它对外接收用户请求,对内调度模型层和模版层,统合数据库和前端,最后根据业务逻辑,将处理好的数据,与前端结合,返回给用户。视图层是真正的后端,是 Python工程师的‘主营业务’。Django 的视图层包含下面一些主要内容:

  1.URL 路由

  2.视图函数

  3.快捷方式

  4.请求与响应

一、URL 路由基础

URL 是 Web 服务的入口,用户通过浏览器发送过来的任何请求,都是发送到一个指定的 URL 地址,然后被响应。

在 Django 项目中编写路由,就是向外暴露我们接收哪些 URL 的请求,除此之外的任何 URL 都不被处理,也没有返回。通俗地理解,不恰当的形容,URL 路由是你的 Web服务对外暴露的 API。

URL 路由在 Django 项目中的体现就是 urls.py 文件,这个文件可以有很多个。实际上Django 提倡项目有个根 urls.py,各 app 下分别有自己的一个 urls.py,既集中又分治,是一种解耦的模式。

随便新建一个 Django 项目,默认会自动为我们创建一个/project_name/urls.py 文件,并且自动包含下面的内容,这就是项目的根 URL:

前面一堆帮助性的文字,我们不用管,关键是默认导入了 url 和 admin,然后有一条指向 admin 后台的 url 路径。

我们自己要编写的 url 路由,基本也是这个套路。

1、Django 如何处理请求

当用户请求一个页面时,Django 根据下面的逻辑执行操作:

(1)决定要使用的根 URLconf 模块。通常,这是 ROOT_URLCONF 设置的值,你可以自定义项目入口 url 是哪个文件。

(2) 加载该模块并寻找可用的 urlpatterns。 它是 django.conf.urls.url()实例的一个列表。

(3) 依次匹配每个 URL 模式,在与请求的 URL 相匹配的第一个模式停下来。也就是说,url 匹配是从上往下的短路操作,所以 url 在列表中的位置非常关键。

(4)导入并调用匹配行中给定的视图,该视图是一个简单的 Python 函数(被称为视图函数),或基于类的视图。 视图将获得如下参数:

  (01)  一个 HttpRequest 实例。

  (02)  如果匹配的正则表达式返回了没有命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图。

  (03)  关键字参数由正则表达式匹配的命名组组成,但是可以被django.conf.urls.url()的可选参数 kwargs 覆盖。

(5)如果没有匹配到正则表达式,或者过程中抛出异常,将调用一个适当的错误处理视图。

简单示例

下面是一个简单的 URLconf:

from django.conf.urls import url
from booktest import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

我们要编写的就是上面 urlpatterns 列表中的一条条 url,每条 url,都是 urlpatterns 列表的一个元素。先后顺序有重要关系,不能随意摆放。最后一条的末尾建议

添加一个逗号。

urlpatterns 中的每条正则表达式在第一次访问时被自动编译,因此其匹配速度是非常快的。

注意:

1.若要从 URL 中捕获一个值,只需要在它周围放置一对圆括号。

2.  不需要添加前导的反斜杠,因为每个 URL 都有。 例如,应该是^articles 而不是^/articles。

3.  每个正则表达式前面的'r'是可选的但是建议加上。它告诉 Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义。

根据上面的 urlconf,下面是一些请求的例子,以及它们将匹配到的 url:

1.  /articles/2005/03/将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, '2005', '03')。

2.  /articles/2005/3/不匹配任何 URL 模式,因为列表中的第三个模式要求月份是两个数字。

3./articles/2003/将匹配列表中的第一个模式不是第二个,因为模式按顺序从上往下匹配,第一个会首先被匹配。Django 会调用函数views.special_case_2003(request)

4.  /articles/2003 不匹配任何一个模式,因为每个模式都要求 URL 以一个斜杠结尾。

5.  /articles/2003/03/03/将匹配最后一个模式。Django 将调用函数views.article_detail(request, '2003', '03', '03')。

2、命名组

很多时候,我们需要获取 URL 中的一些片段,作为参数,传递给处理请求的视图。

上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获 URL 中的值并以位置参数的形式传递给视图。

可以使用命名的正则表达式组来捕获 URL 中的值并以关键字参数传递给视图。

在 Python 的正则表达式中,命名组的语法是(?P<name>pattern),其中 name 是组的名称,pattern 是要匹配的模式。

下面是以上 URLconf 使用命名组的重写:

from django.conf.urls import url
from . import views
urlpatterns = [
  url(r'^articles/2003/$', views.special_case_2003),
  url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
  url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$',views.month_archive),
  url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。 像这样:

1. /articles/2005/03/请求将调用 views.month_archive(request, year='2005',month='03')函数,而不是 views.month_archive(request, '2005', '03')。

2.  /articles/2003/03/03/请求将调用函数 views.article_detail(request,year='2003', month='03', day='03')。

在实际应用中,这让你的 URLconf 更加明晰且不容易产生参数顺序问题的错误。针对命名组和非命名组:

 1.如果有命名参数,则使用这些命名参数,忽略非命名参数。

  2.否则,它将以位置参数传递所有的非命名参数。

3、URLconf 匹配请求 URL

请求的 URL 被看做是一个普通的 Python 字符串,URLconf 在其上查找并匹配。进行匹配时将不包括 GET 或 POST 请求方式的参数以及域名。

例如,在 https://www.example.com/myapp/的请求中,URLconf 将查找 myapp/。

在 https://www.example.com/myapp/?page=3 的请求中,URLconf 也将查找 myapp/。

URLconf 不检查使用何种 HTTP 请求方法,所有请求方法 POST、GET、HEAD 等都将路由到同一个 URL 的同一个视图。在视图中,才根据具体请求方法的不同,进行不同的处理。

4、URL 中捕获的参数为字符串类型

每个捕获的参数都作为一个普通的 Python 字符串传递给视图,即便被捕获的‘100’看起来像个整数,但实际上是个字符串‘100’。 例如,下面这行 URLconf 中:

  url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

传递给 views.year_archive()的 year 参数将是一个字符串,不是整数,即使[0-9]{4}只匹配整数字符串。

5、指定视图参数的默认值

有一个小技巧,我们可以指定视图参数的默认值。 下面是一个 URLconf 和视图的示例:

# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
  url(r'^blog/$', views.page),
  url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
# View (in blog/views.py)
def page(request, num="1"):
  # Output the appropriate page of blog entries, according to num.
  ...

在上面的例子中,两个 URL 模式指向同一个视图 views.page。但是第一个模式不会从URL 中捕获任何值。 如果第一个模式匹配,page()函数将使用 num 参数的默认值"1"。如果第二个模式匹配,page()将使用捕获的 num 值。

二、路由转发

通常,我们会在每个 app 里,各自创建一个 urls.py 路由模块,然后从根路由出发,将app 所属的 url 请求,全部转发到相应的 urls.py 模块中。

例如,下面是 Django 网站本身的 URLconf 节选。 它包含许多其它 URLconf:

from django.conf.urls import include, url
urlpatterns = [
  url(r'^community/', include('django_website.aggregator.urls')),
  url(r'^contact/', include('django_website.contact.urls')),
]

路由转发使用的是 include()方法,需要提前导入,它的参数是转发目的地路径的字符串,路径以圆点分割。

注意,这个例子中的正则表达式没有包含$(字符串结束匹配符),但是包含一个末尾的斜杠。 每当 Django 遇到 include()时,它会去掉 URL 中匹配的部分并将剩下的字符串发送给 include 的 URLconf 做进一步处理,也就是转发到二级路由去。

看下面的 URLconf:

from django.conf.urls import url
from . import views
urlpatterns = [
  url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),
  url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),
  url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),
  url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$',views.permissions),
]

上面的路由写得不好,我们可以改进它,只需要声明共同的路径前缀一次,并将后面的部分分组转发:

from django.conf.urls import include, url
from . import views
urlpatterns = [
  url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
    url(r'^history/$', views.history),
    url(r'^edit/$', views.edit),
    url(r'^discuss/$', views.discuss),
    url(r'^permissions/$', views.permissions),
  ])),
]

这样就优雅多了,也清爽多了。

1、捕获参数

被转发的 URLconf 会收到来自父 URLconf 捕获的所有参数,看下面的例子:

# In settings/urls/main.py
from django.conf.urls import include, url
urlpatterns = [
  url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
]
# In foo/urls/blog.py
from django.conf.urls import url
from . import views
urlpatterns = [
  url(r'^$', views.blog.index),
  url(r'^archive/$', views.blog.archive),
]

在上面的例子中,捕获的"username"变量将被传递给 include()指向的 URLconf,再进一步传递给对应的视图。

2、向视图传递额外的参数

URLconfs 具有一个钩子(hook),允许你传递一个 Python 字典作为额外的关键字参数给视图函数。

像这样:

from django.conf.urls import url
from . import views
urlpatterns = [
  url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

在上面的例子中,对于/blog/2005/请求,Django 将调用 views.year_archive(request,year='2005', foo='bar')。理论上,你可以在这个字典里传递任何你想要的传递的东西。但是要注意,URL 模式捕获的命名关键字参数和在字典中传递的额外参数有可能具有

相同的名称,这会发生冲突,要避免。

3、传递额外的参数给 include()

类似上面,也可以传递额外的参数给 include()。参数会传递给 include 指向的 urlconf中的每一行。

例如,下面两种 URLconf 配置方式在功能上完全相同:

配置一:

# main.py
from django.conf.urls import include, url
urlpatterns = [
  url(r'^blog/', include('inner'), {'blogid': 3}),
]
# inner.py
from django.conf.urls import url
from mysite import views
urlpatterns = [
  url(r'^archive/$', views.archive),
  url(r'^about/$', views.about),
]

配置二:

# main.py
from django.conf.urls import include, url
from mysite import views
urlpatterns = [
  url(r'^blog/', include('inner')),
]
# inner.py
from django.conf.urls import url
urlpatterns = [
  url(r'^archive/$', views.archive, {'blogid': 3}),
  url(r'^about/$', views.about, {'blogid': 3}),
]

注意,只有当你确定被 include 的 URLconf 中的每个视图都接收你传递给它们的额外的参数时才有意义,否则其中一个以上视图不接收该参数都将导致错误异常。

4、URL 反向解析和命名空间

如果在视图、模板中使用硬编码的链接,在 urlconf 发生改变时,维护是一件非常麻烦的事情。我们需要一种安全、可靠、自适应的机制,当修改 URLconf 中的代码后,无需在项目源码中大范围搜索、替换失效的硬编码 URL。为了解决这个问题,Django 提供了一

种解决方案,只需在 URL 中提供一个 name 参数,并赋值一个你自定义的、好记的、直观的字符串。通过这个 name 参数,可以反向解析 URL、反向 URL 匹配、反向 URL 查询或者简单的URL 反查。

在需要解析 URL 的地方,对于不同层级,Django 提供了不同的工具用于 URL 反查:

  1.在模板语言中:使用 url 模板标签。(也就是写前端网页时)

  2.在 Python 代码中:使用 reverse()函数。(也就是写视图函数等情况时)

  3.在更高层的与处理 Django 模型实例相关的代码中:使用 get_absolute_url()方法。(也就是在模型 model 中)

范例:

考虑下面的 URLconf:

from django.conf.urls import url
from . import views
urlpatterns = [
  url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
]

某一年 nnnn 对应的归档的 URL 是/articles/nnnn/。

可以在模板的代码中使用下面的方法获得它们:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a> # 注意模版语言的用法,注意参数的传递方法

在 Python 代码中,这样使用:

from django.urls import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
  year = 2006
  # ...注意参数的传递方法
  return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

其中,起到核心作用的是我们通过 name='news-year-archive'为那条 url 起了一个可以被引用的名称。

URL 命名空间

URL 命名空间可以保证反查到唯一的 URL,即使不同的 app 使用相同的 URL 名称。

第三方应用始终使用带命名空间的 URL 是一个很好的做法。

include()中设置 namespace 参数

url()中设置 name 参数

可以以 namespace:name 来访问 url。

三、视图函数及快捷方式

视图函数,简称视图,本质上是一个简单的 Python 函数,它接受 Web 请求并且返回Web 响应。

响应的内容可以是 HTML 网页、重定向、404 错误,XML 文档或图像等任何东西。但是,无论视图本身是个什么处理逻辑,最好都返回某种响应。

视图函数的代码写在哪里也无所谓,只要它在你的 Python 目录下面。但是通常我们约定将视图放置在项目或应用程序目录中的名为 views.py 的文件中。

1、简单的视图

下面是一个返回当前日期和时间作为 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)

让我们逐行分析一下上面的代码:

  1.首先,从 django.http 模块导入了 HttpResponse 类,以及 Python 的 datetime库。

  2.接着,我们定义了 current_datetime 视图函数。

  3.每个视图函数都接收一个 HttpRequest 对象作为第一位置参数,一般取名为request,你可以取别的名字,但这不符合潜规则,最好不要那么做。

  4.  视图函数的名称没有强制规则,但尽量不要和 Python 及 Django 内置的各种名称重名,并且尽量精确地反映出它的功能,比如这里的 current_datetime。该视图返回一个 HttpResponse 对象,其中包含生成的 HTML 页面。

2、返回错误

在 Django 中返回 HTTP 错误代码是非常简单的。

HttpResponse 的许多子类对应着除了 200(代表“OK”)以外的一些常用的 HTTP 状态码。

为了标示一个错误,可以直接返回那些子类中的一个实例,而不是普通的HttpResponse。像下面这样:

from django.http import HttpResponse, HttpResponseNotFound
def my_view(request):
  if foo:
    return HttpResponseNotFound('<h1>Page not found</h1>')
  else:
    return HttpResponse('<h1>Page was found</h1>')

Django 为 404 错误提供了一个特化的子类 HttpResponseNotFound。由于一些状态码不太常用,所以不是每个状态码都有一个特化的子类。

也可以向 HttpResponse 的构造器传递 HTTP 状态码,来创建你想要的任何状态码的返回类。 像下面这样:

from django.http import HttpResponse
def my_view(request):
  # Return a "created" (201) response code.
  return HttpResponse(status=201)

关键是在返回中提供 status=201 参数。别的什么 303 之类的错误都可以参照上面的例子。

3、Http404 异常

class django.http.Http404

这是一个 Django 内置的异常类。可以在需要的地方认为弹出它,Django 会捕获它,并且带上 HTTP404 错误码返回你当前 app 的标准错误页面或者自定义错误页面。像下面这样:

from django.http import Http404
from django.shortcuts import render
from polls.models import Poll
def detail(request, poll_id):
  try:
    p = Poll.objects.get(pk=poll_id)
  except Poll.DoesNotExist:
    raise Http404("Poll does not exist")
  return render(request, 'polls/detail.html', {'poll': p})

3、Django 内置的快捷方法

Django 在 django.shortcuts 模块中,为我们提供了很多快捷方便的类和方法,它们都很重要,使用频率很高。

render()

render(request, template_name, context=None, content_type=None, status=None,using=None)[source]

结合一个给定的模板和一个给定的上下文字典,返回一个渲染后的 HttpResponse 对象。

必需参数:

  1.request:视图函数处理的当前请求,封装了请求头的所有数据,其实就是视图参数 request。

  2.  template_name:要使用的模板的完整名称或者模板名称的列表。如果是一个列表,将使用其中能够查找到的第一个模板。

可选参数:

  1.context:添加到模板上下文的一个数据字典。默认是一个空字典。可以将认可需要提供给模板的数据以字典的格式添加进去。

  2.content_type:用于生成的文档的 MIME 类型。 默认为DEFAULT_CONTENT_TYPE 设置的值。

  3.status:响应的状态代码。 默认为 200。

  4.using:用于加载模板使用的模板引擎的 NAME。

范例:

下面的例子将渲染模板 myapp/index.html,MIME 类型为 application/xhtml+xml:

from django.shortcuts import render
def my_view(request):
  # View code here...
  return render(request, 'myapp/index.html', {'foo': 'bar',}, content_type='application/xhtml+xml')

这个示例等同于:

from django.http import HttpResponse
from django.template import loader
def my_view(request):
  # View code here...
  t = loader.get_template('myapp/index.html')
  c = {'foo': 'bar'}
  return HttpResponse(t.render(c, request),content_type='application/xhtml+xml')

redirect()

redirect(to, permanent=False, args, *kwargs)[source]

根据传递进来的 url 参数,返回 HttpResponseRedirect。

参数 to 可以是:

  1.一个模型:将调用模型的 get_absolute_url()函数,反向解析出目的 url;

  2.  url 名称:可能带有参数,reverse()将用于反向解析 url;

  3.一个绝对的或相对的 URL:将原封不动的作为重定向的目标位置。默认情况下是临时重定向,如果设置 permanent=True 将永久重定向。

范例:

调用对象的 get_absolute_url()方法来重定向 URL:

from django.shortcuts import redirect
def my_view(request):
  object = MyModel.objects.get(...)
  return redirect(object)

使用 reverse()方法反向解析 url:

def my_view(request):
  ...
  return redirect(reverse('some-view-name', foo='bar'))

重定向到硬编码的 URL:

def my_view(request):
  ...
  return redirect('/some/url/')

重定向到一个完整的 URL:

def my_view(request):
  ...
  return redirect('https://example.com/')

所有上述形式都接受 permanent 参数;如果设置为 True,将返回永久重定向:

def my_view(request):
  ...
  object = MyModel.objects.get(...)
  return redirect(object, permanent=True)

get_object_or_404()

get_object_or_404(klass, args, *kwargs)[source]

这个方法,非常有用,请一定熟记。常用于查询某个对象,找到了则进行下一步处理,如果未找到则给用户返回 404 页面。

在后台,Django 其实是调用了模型管理器的 get()方法,只会返回一个对象。不同的是,如果 get()发生异常,会引发 Http404 异常,从而返回 404 页面,而不是模型的DoesNotExist 异常。

必需参数:

  1.klass:要获取的对象的 Model 类名或者 Queryset 等;

  2.**kwargs:查询的参数,格式应该可以被 get()接受。

范例:

从 MyModel 中使用主键 1 来获取对象:

from django.shortcuts import get_object_or_404
def my_view(request):
  my_object = get_object_or_404(MyModel, pk=1)

除了传递 Model 名称,还可以传递一个 QuerySet 实例:

  get_object_or_404(Book, title__startswith='M', pk=1)

get_list_or_404()

get_list_or_404(klass, args, *kwargs)[source]

这其实就是 get_object_or_404 多值获取版本。

在后台,返回一个给定模型管理器上 filter()的结果,并将结果映射为一个列表,如果结果为空则弹出 Http404 异常。

必需参数:

  1.klass:获取该列表的一个 Model、Manager 或 QuerySet 实例。

  2.**kwargs:查询的参数,格式应该可以被 filter()接受。

范例:

下面的示例从 MyModel 中获取所有发布出来的对象:

from django.shortcuts import get_list_or_404
def my_view(request):
  my_objects = get_list_or_404(MyModel, published=True)

四、HttpRequest 对象

每当一个用户请求发送过来,Django 将 HTTP 数据包中的相关内容,打包成为一个HttpRequest 对象,并传递给每个视图函数作为第一位置参数,也就是 request,供我们调用。

HttpRequest 对象中包含了非常多的重要的信息和数据,应该熟练掌握它。

1、属性

HttpRequest 对象的大部分属性是只读的,除非特别注明。

HttpRequest.scheme

字符串类型,表示请求的协议种类,'http'或'https'。

HttpRequest.body

bytes 类型,表示原始 HTTP 请求的正文。它对于处理非 HTML 形式的数据非常有用:二进制图像、XML 等。如果要处理常规的表单数据,应该使用 HttpRequest.POST。还可以使用类似读写文件的方式从 HttpRequest 中读取数据,参见 HttpRequest.read()。

HttpRequest.path

字符串类型,表示当前请求页面的完整路径,但是不包括协议名和域名。例如:"/music/bands/the_beatles/"。这个属性,常被用于我们进行某项操作时,如果不通过,返回用户先前浏览的页面。非常有用!

HttpRequest.path_info

在某些 Web 服务器配置下,主机名后的 URL 部分被分成脚本前缀部分和路径信息部分。path_info 属性将始终包含路径信息部分,不论使用的 Web 服务器是什么。使用它代替 path 可以让代码在测试和开发环境中更容易地切换。

HttpRequest.method

字符串类型,表示请求使用的 HTTP 方法。默认为大写。 像这样:

if request.method == 'GET':
  do_something()
elif request.method == 'POST':
  do_something_else()

通过这个属性来判断请求的方法,然后根据请求的方法不同,在视图中执行不同的代码。

HttpRequest.encoding

字符串类型,表示提交的数据的编码方式(如果为 None 则表示使用DEFAULT_CHARSET 设置)。 这个属性是可写的,可以通过修改它来改变表单数据的编码。任何随后的属性访问(例如 GET 或 POST)将使用新的编码方式。

HttpRequest.content_type

表示从 CONTENT_TYPE 头解析的请求的 MIME 类型。

HttpRequest.content_params

包含在 CONTENT_TYPE 标题中的键/值参数字典。

HttpRequest.GET

一个类似于字典的对象,包含 GET 请求中的所有参数。 详情参考 QueryDict。

HttpRequest.POST

一个包含所有 POST 请求的参数,以及包含表单数据的字典。 详情请参考 QueryDict。如果需要访问请求中的原始或非表单数据,可以使用 HttpRequest.body 属性。

注意:请使用 if request.method == "POST"来判断一个请求是否 POST 类型,而不要使用 if request.POST。

POST 中不包含上传文件的数据。

HttpRequest.COOKIES

包含所有 Cookie 信息的字典。 键和值都为字符串。可以类似字典类型的方式,在cookie 中读写数据,但是注意 cookie 是不安全的,因此,不要写敏感重要的信息。

HttpRequest.FILES

一个类似于字典的对象,包含所有上传的文件数据。 FILES 中的每个键为<input type="file" name="" />中的 name 属性值。 FILES 中的每个值是一个 UploadedFile。要在 Django 中实现文件上传,就要靠这个属性!

HttpRequest.META

包含所有 HTTP 头部信息的字典。 可用的头部信息取决于客户端和服务器,下面是一些示例:

  CONTENT_LENGTH —— 请求正文的长度(以字符串计)。

  CONTENT_TYPE —— 请求正文的 MIME 类型。

  HTTP_ACCEPT —— 可接收的响应 Content-Type。

  HTTP_ACCEPT_ENCODING —— 可接收的响应编码类型。

  HTTP_ACCEPT_LANGUAGE —— 可接收的响应语言种类。

  HTTP_HOST —— 客服端发送的 Host 头部。

  HTTP_REFERER —— Referring 页面。

  HTTP_USER_AGENT —— 客户端的 user-agent 字符串。

  QUERY_STRING —— 查询字符串。

  REMOTE_ADDR —— 客户端的 IP 地址。想要获取客户端的 ip 信息,就在这里!

  REMOTE_HOST —— 客户端的主机名。

  REMOTE_USER —— 服务器认证后的用户,如果可用。

  REQUEST_METHOD —— 表示请求方法的字符串,例如"GET" 或"POST"。

  SERVER_NAME —— 服务器的主机名。

  SERVER_PORT —— 服务器的端口(字符串)。

以上只是比较重要和常用的,还有很多未列出。

HttpRequest.resolver_match

代表一个已解析的 URL 的 ResolverMatch 实例。Django 不会自动设置下面这些属性,而是由你自己在应用程序中设置并使用它们。

HttpRequest.current_app

表示当前 app 的名字。url 模板标签将使用其值作为 reverse()方法的 current_app 参数。

HttpRequest.urlconf

设置当前请求的根 URLconf,用于指定不同的 url 路由进入口,这将覆盖 settings 中的ROOT_URLCONF 设置。将它的值修改为 None,可以恢复使用 ROOT_URLCONF 设置。

由中间件设置的属性

Django 的 contrib 应用中包含的一些中间件会在请求上设置属性。

HttpRequest.session

SessionMiddleware 中间件:一个可读写的,类似字典的对象,表示当前会话。我们要保存用户状态,回话过程等等,靠的就是这个中间件和这个属性。

HttpRequest.site

CurrentSiteMiddleware 中间件:get_current_site()方法返回的 Site 或 RequestSite 的实例,代表当前站点是哪个。

Django 是支持多站点的,如果你同时上线了几个站点,就需要为每个站点设置一个站点 id。

HttpRequest.user

AuthenticationMiddleware 中间件:表示当前登录的用户的 AUTH_USER_MODEL 的实例,这个模型是 Django 内置的 Auth 模块下的 User 模型。如果用户当前未登录,则user 将被设置为 AnonymousUser 的实例。

2、方法

HttpRequest.get_host()[source]

根据 HTTP_X_FORWARDED_HOST 和 HTTP_HOST 头部信息获取请求的原始主机。 如果这两个头部没有提供相应的值,则使用 SERVER_NAME 和 SERVER_PORT。

例如:"127.0.0.1:8000"

HttpRequest.get_port()[source]

使用 META 中 HTTP_X_FORWARDED_PORT 和 SERVER_PORT 的信息返回请求的始发端口。

HttpRequest.get_full_path()[source]

返回包含完整参数列表的 path。例如:/music/bands/the_beatles/?print=true

HttpRequest.build_absolute_uri(location)[source]

返回 location 的绝对 URI 形式。 如果 location 没有提供,则使用request.get_full_path()的值。

例如:"https://example.com/music/bands/the_beatles/?print=true"

HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='',max_age=None)[source]

从已签名的 Cookie 中获取值,如果签名不合法则返回django.core.signing.BadSignature。

HttpRequest.is_secure()[source]

如果使用的是 Https,则返回 True,表示连接是安全的。

HttpRequest.is_ajax()[source]

如果请求是通过 XMLHttpRequest 生成的,则返回 True。

这个方法的作用就是判断,当前请求是否通过 ajax 机制发送过来的。

HttpRequest.read(size=None)[source]

HttpRequest.readline()[source]

HttpRequest.readlines()[source]

HttpRequest.xreadlines()[source]

HttpRequest.iter()

上面的几个方法都是从 HttpRequest 实例读取文件数据的方法。

五、QueryDict 对象

在 HttpRequest 对象中,GET 和 POST 属性都是一个 django.http.QueryDict 的实例。也就是说你可以按本文下面提供的方法操作 request.POST 和 request.GET。

request.POST 或 request.GET 的 QueryDict 都是不可变,只读的

如果要修改它,需要使用QueryDict.copy()方法,获取它的一个拷贝,然后在这个拷贝上进行修改操作。

1、方法

QueryDict 实现了 Python 字典数据类型的所有标准方法,因为它是字典的子类。

不同之处在于下面:

1.1 QueryDict 实例化方法。注意:QueryDict 的键值是可以重复的!

>>> QueryDict('a=1&a=2&c=3')
<QueryDict: {'a': ['1', '2'], 'c': ['3']}>

1.2. 循环可迭代对象中的每个元素作为键值,并赋予同样的值(来至 value 参数)。

>>> QueryDict.fromkeys(['a', 'a', 'b'], value='val')
<QueryDict: {'a': ['val', 'val'], 'b': ['val']}>

1.3. QueryDict.update(other_dict)

用新的 QueryDict 或字典更新当前 QueryDict。类似 dict.update(),但是追加内容,而不是更新并替换它们。 像这样:

>>> q = QueryDict('a=1', mutable=True)
>>> q.update({'a': '2'})
>>> q.getlist('a')
['1', '2']

1.4. QueryDict.items()

类似 dict.items(),如果有重复项目,返回最近的一个,而不是都返回:

>>> q = QueryDict('a=1&a=2&a=3')
>>> q.items()
[('a', '3')]

1.5. QueryDict.values()

类似 dict.values(),但是只返回最近的值。 像这样:

>>> q = QueryDict('a=1&a=2&a=3')
>>> q.values()
['3']

1.6. QueryDict.copy()[source]

使用 copy.deepcopy()返回 QueryDict 对象的副本。 此副本是可变的!

1.7. QueryDict.getlist(key, default=None)

返回键对应的值列表。 如果该键不存在并且未提供默认值,则返回一个空列表。

1.8. QueryDict.setlist(key, list_)[source]

为 list_设置给定的键。

1.9. QueryDict.appendlist(key, item)[source]

将键追加到内部与键相关联的列表中。

1.10. QueryDict.setdefault(key, default=None)[source]

类似 dict.setdefault(),为某个键设置默认值。

1.11. QueryDict.setlistdefault(key, default_list=None)[source]

类似 setdefault(),除了它需要的是一个值的列表而不是单个值。

1.12. QueryDict.lists()

类似 items(),只是它将其中的每个键的值作为列表放在一起。 像这样:

>>> q = QueryDict('a=1&a=2&a=3')
>>> q.lists()
[('a', ['1', '2', '3'])]

1.13. QueryDict.pop(key)[source]

返回给定键的值的列表,并从 QueryDict 中移除该键。 如果键不存在,将引发KeyError。 像这样:

1.14. QueryDict.popitem()[source]

删除 QueryDict 任意一个键,并返回二值元组,包含键和键的所有值的列表。在一个空的字典上调用时将引发 KeyError。 像这样:

>>> q = QueryDict('a=1&a=2&a=3', mutable=True)
>>> q.popitem()
('a', ['1', '2', '3'])

1.15. QueryDict.dict()

将 QueryDict 转换为 Python 的字典数据类型,并返回该字典。如果出现重复的键,则将所有的值打包成一个列表,作为新字典中键的值。

>>> q = QueryDict('a=1&a=3&a=5')
>>> q.dict()
{'a': '5'}

1.16. QueryDict.urlencode(safe=None)[source]

以 url 的编码格式返回数据字符串。 像这样:

>>> q = QueryDict('a=2&b=3&b=5')
>>> q.urlencode()
'a=2&b=3&b=5'

2. Get 属性

QueryDict 类型的对象

包含 get 请求方法的所有参数

与 url 请求地址中的参数对应,位于?后面

参数的格式是键值对,如 key1=value1

多个参数之间,使用&连接,如 key1=value1& key2=value2

键是开发人员定下来的,值是可变的

具体示例参堂代码。

3. Post 属性

QueryDict 类型的对象

包含 post 请求方式的所有参数

与 form 表单中的控件对应

控件要有 name 属性,name 属性的值为键,其 value 属性的值为值,构成键值对提交

键是开发人员定下来的,值是可变的具体示例参见课堂代码。

七、 状态保持

会话过期时间

  1.set_expiry(value):设置会话的超时时间

  2.如果没有指定,则两个星期后过期

  3.如果 value 是一个整数,会话将在 values 秒没有活动后过期

  4.如果 value 是一个 timedelta 对象(时间间隔),会话将在当前时间上加上这个指定的日期/时间过期

  5.如果 value 为 0,那么用户会话的 cookie 将在用户的浏览器关闭时过期

  6. 如果 value 为 None,那么会话永不过期

 

posted @ 2019-02-26 22:40  ^sun^  阅读(1010)  评论(0编辑  收藏  举报