【Django 笔记】视图---URL路由、自定义错误页面、HttpRequest对象、Ajax、Cookie、session

 

笔记主要基于官方文档,从中提取要点和记录笔记,关键处包含了官方文档链接。详见官方文档。

官方文档:Django documentation 

博客推荐:Django2.2教程

官方文档视图层:视图层

目录

1.URL路由

1.1.URL配置过程(重要)

1.2.Django 如何处理一个请求(了解)

......

2.自定义错误页面

3.HttpRequest objects

4.Ajax

5.Cookie

6.session


 

视图

视图负责接受Web请求HttpRequest,进行逻辑处理,与M和T进行交互,返回Web响应HttpResponse给请求者。也可能重定向 redirect,还可以返回json数据

 

使用视图的过程

视图就是一个python函数,被定义在"应用/views.py"文件中。 使用视图时需要进行两方面操作,两个操作不分先后。

1)在"应用/views.py"中定义视图

2)配置URLconf,将视图函数和url对应起来

 

1.URL路由

部分相关官方文档:

  • path函数等:django.urls functions for use in URLconfs、
  • URL调度器(处理请求、路径转换器、使用正则表达式、URLconf匹配URL中的哪些部分、包含其它的URLconfs(路由转发)、URL 的反向解析 等)

博客:https://www.liujiangblog.com/course/django/134

 

Django开发的网站,由哪一个视图进行处理请求,是由url匹配找到的。所以需要配置URLconf,将视图函数和url对应起来。

URL路由在Django项目中的体现就是urls.py文件,提倡项目有个urls.py,各app下各有一个app urls.py,既集中又分治,是一种解耦的模式。

:路由的编写方式是Django2.x和1.x最大的区别所在。Django官方将原来的正则匹配表达式,改为更加简单的path表达式,但依然通过re_path()方法保持对1.x版本的兼容

 

1.1.URL配置过程(重要)

  1. 在项目的urls文件中包含具体应用的urls文件,在具体应用的urls文件中包含具体url和视图的对应关系。
  2. url配置项是定义在一个名叫urlpatterns的列表中,其中的每一个元素就是一个配置项,每一个配置项都调用url函数。

具体配置例子和path函数可参考入门篇的:编写视图和URLConf

 

1.2.Django 如何处理一个请求(了解)

可能在URL配置过程中,可能会知其然而不知其所以然,这就需要了解Django 如何处理一个请求(跳转官方文档)。

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

  1. 决定要使用的根URLconf模块。。通常,这是 ROOT_URLCONF 设置的值,但如果传入 HttpRequest 对象拥有 urlconf 属性(通过中间件设置),它的值将被用来代替 ROOT_URLCONF 设置。通俗的讲,就是可以自定义项目入口url是哪个文件!
  2. Django 加载该模块并寻找可用的 urlpatterns 。它是 django.urls.path() 和(或) django.urls.re_path() 实例的一个列表(sequence)。
  3. Django 依次匹配每个URL 模式,在与请求的URL 匹配的第一个模式停下来。即url匹配是从上往下的短路操作,所以url在列表中的位置非常关键。
  4. 一旦有 URL 匹配成功,Djagno 导入并调用相关的视图,这个视图是一个简单的 Python 函数(或基于类的视图 class-based view )。视图会获得如下参数:
    • 一个 HttpRequest 实例。
    • 如果匹配的 URL返回了没有命名的组,那么匹配的内容将作为位置参数提供给视图。
    • 关键字参数由表达式匹配的命名组组成,并由 django.urls.path() 或 django.urls.re_path() 的可选 kwargs 参数中指定的任何参数覆盖。
  5. 如果没有 URL 被匹配,或者匹配过程中出现了异常,Django 会调用一个适当的错误处理视图。参加下面的错误处理( Error handling )。

 

1.3.路径转换器

默认情况下,Django内置下面的路径转换器:

  • str:匹配任何非空字符串,但不含斜杠/,如果你没有专门指定转换器,那么这个是默认使用的;
  • int:匹配0和正整数,返回一个int类型
  • slug:可理解为注释、后缀、附属等概念,是url拖在最后的一部分解释性字符。该转换器匹配任何ASCII字符以及连接符和下划线,比如building-your-1st-django-site
  • uuid:匹配一个uuid格式的对象。为了防止冲突,规定必须使用破折号,所有字母必须小写,例如075194d3-6885-417e-a8a8-6c931e272f00。返回一个UUID对象;
  • path:匹配任何非空字符串,重点是可以包含路径分隔符’/‘。这个转换器可以帮助你匹配整个url而不是一段一段的url字符串。要区分path转换器和path()方法

路径转换器用于path的参数route

 

下面是一个简单的 URLconf:

from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles//', views.year_archive),
    path('articles///', views.month_archive),
    path('articles////', views.article_detail),
]

 

1.4.指定视图参数的默认值

有一个方便的小技巧是指定视图参数的默认值。 下面是一个URLconf 和视图的示例:

# URLconf url.py文件

from django.urls import path

from . import views

urlpatterns = [
    path('blog/', views.page),
    path('blog/page/', 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值。

 

1.5.捕获的参数

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

# In settings/urls/main.py   父URLconf
from django.urls import include, path

urlpatterns = [
    path('/blog/', include('foo.urls.blog')),
]


# In foo/urls/blog.py  目的地URLconf
from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog.index),
    path('archive/', views.blog.archive),
]

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

 

1.6.向视图传递额外的参数

URLconfs具有一个钩子(hook),允许把其他参数作为 Python 字典来传递给视图函数,像下面这样:

from django.urls import path
from . import views

urlpatterns = [
    path('blog//', views.year_archive, {'foo': 'bar'}),
]

在上面的例子中,当请求到 /blog/2005/ 时,Django将调views.year_archive(request, year='2005', foo='bar')。理论上,你可以在这个字典里传递任何你想要的传递的东西。在 syndication framework 中使用了这个办法,来向视图传递元数据和可选参数

注意,URL模式捕获的命名关键字参数和在字典中传递的额外参数有可能具有相同的名称,这会发生冲突,要避免。

 

1.7.传递额外参数给 include()

类似上面,也可以传递额外的参数给 include() 。参数会传递给include指向的urlconf中的每一行,不管视图是否接受这些额外参数。因此,这个技巧仅在确定所包含的 URLconf 中的每一个视图接受你传递的额外选项时有用。

下面两个 URLconf 配置在功能上是相同的:

配置一:

# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path('blog/', include('inner')),
]

# inner.py
from django.urls import path

urlpatterns = [
    path('archive/', views.archive, {'blog_id': 3}),
    path('about/', views.about, {'blog_id': 3}),
]

配置二:

# main.py
from django.urls import include, path

urlpatterns = [
    path('blog/', include('inner'), {'blog_id': 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path('archive/', views.archive),
    path('about/', views.about),
]

 

更多关于URLconf内容请参考官方文档


 

2.自定义错误页面

当 Django 找不到所匹配的请求 URL 时,或引发了异常时,Django 会调用一个错误处理视图。

Django默认的自带的错误视图包括400、403、404500,分别表示请求错误拒绝服务页面不存在服务器错误。它们的默认值应该满足大部分项目,但是通过赋值给它们以进一步的自定义也是可以的。

这些值是:

  • handler400 -- 查看 django.conf.urls.handler400.
  • handler403 -- 查看 django.conf.urls.handler403.
  • handler404 -- 查看 django.conf.urls.handler404.
  • handler500 -- 查看 django.conf.urls.handler500.

这些值可以在根URLconf中设置。在其它app中的二级URLconf中设置这些变量无效。

 

Django有内置的HTML模版,用于返回错误页面给用户,但是这些403,404页面太简陋,通常都自定义错误页面。

完整的细节请参见 自定义错误视图 。

实例:

(一)只需要简单的自定义错误页面时,在全局的templates根目录下,创建对应的400.html、403.html、404.html、500.html页面文件即可。Django会自动调用html。{{ request_path }}获取请求路径。如下




    
    404错误页面


页面找不到--{{ request_path }}

 

(二)

(1)在根URLconf中(项目的根urls.py文件)额外增加下面的条目,并导入app的views模块:

from django.contrib import admin
from django.urls import path
from appname import views

urlpatterns = [
    path('admin/', admin.site.urls),
    #...
]

# 增加的条目
handler400 = views.bad_request
handler403 = views.permission_denied
handler404 = views.page_not_found
handler500 = views.server_error

(2)在app的 views.py 文件中增加四个处理视图:


def bad_request(request, exception, template_name='400.html'):
    return render(request, template_name)


def permission_denied(request, exception, template_name='403.html'):
    return render(request, template_name)


def page_not_found(request, exception, template_name='404.html'):
    return render(request, template_name, status=404)  # 可以写上status


def server_error(request, template_name='500.html'):
    return render(request, template_name)

(3)根据需求,在全局的templates根目录下创建对应的400.html、403.html、404.html、500.html四个页面文件。

 

:在setting.py中,修改以下两项如下,错误视图才会生效。这两项的修改在网站开发完后必须要做

DEBUG = False

ALLOWED_HOSTS = [‘*’]

 

注意:自定义的视图函数可能会报错。这是由于,不同Django版本下,views模块中自定义的错误处理函数的方法参数可能已经改变,以上基于Django2.2 。

 

 

3.HttpRequest objects

服务器接收到http协议的请求后,会根据报文创建HttpRequest对象(contains metadata about the request),这个对象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数必须是HttpRequest对象(即request,浏览器提交的信息就保存在HttpRequest对象。每个视图负责返回一个HttpResponse对象。

HttpRequest and HttpResponse objects  are defined in the django.http module.  django.http模块可查询相关API。

 

属性

下面除非特别说明,属性都是只读的。

  • path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。print(request.path)可查看
  • method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。
    • 在浏览器中给出地址发出请求采用get方式,如超链接。
    • 在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求。
  • encoding:一个字符串,表示提交的数据的编码方式。
    • 如果为None则表示使用浏览器的默认设置,一般为utf-8。
    • 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
  • GETQueryDict类型对象,类似于字典,包含get请求方式的所有参数。保存的是get方式提交的参数。
  • POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数。保存的是post方式提交的参数。如果需要访问请求中的原始或非表单数据,可以使用HttpRequest.body属性。
  • FILES:一个类似于字典的对象,包含所有的上传文件。
  • COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串。
  • session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见"状态保持"。

更多详情见:HttpRequest。

 

QueryDict对象

  • 定义在django.http.QueryDict
  • QueryDict 实现了Python字典数据类型的所有标准方法,因为它是字典的子类
  • HttpRequest对象的属性GET、POST都是 QueryDict 类型的对象。要了解GET、POST就要先了解QueryDict。
  • 与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
  • 方法get():根据键获取值。QueryDict.get(key, default=None)
  • 如果一个键同时拥有多个值将获取最后一个值
  • 如果键不存在则返回None值,可以设置默认值进行后续处理
dict.get('键',默认值)
可简写为
dict['键']
  • 方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值
  • 如果键不存在则返回空列表[],可以设置默认值进行后续处理
dict.getlist('键',默认值)

 

更多:文档:QueryDict,博客:https://www.liujiangblog.com/course/django/139

 

GET属性

请求格式:在请求地址结尾使用?,之后以"键=值"的格式拼接,多个键值对之间以&连接。

例:网址如下

http://127.0.0.1:8000/?a=10&b=20&c=python

其中的请求参数为:

a=10&b=20&c=python

  • 分析请求参数,键为'a'、'b'、'c',值为'10'、'20'、'python'。
  • 在Django中可以使用HttpRequest对象的GET属性获得get方方式请求的参数。
  • GET属性是一个QueryDict类型的对象,键和值都是字符串类型
  • 键是开发人员在编写代码时确定下来的。
  • 值是根据数据生成的。

POST属性

使用form表单请求时,method方式为post则会发起post方式的请求,需要使用HttpRequest对象的POST属性接收参数,POST属性是一个QueryDict类型的对象。

问:表单form如何提交参数呢?

答:表单控件name属性的值作为键,value属性的值为值,构成键值对提交。

  • 如果表单控件没有name属性则不提交。
  • 对于checkbox控件,name属性的值相同为一组,被选中的项会被提交,出现一键多值的情况。
  • 键是表单控件name属性的值,是由开发人员编写的。
  • 值是用户填写或选择的。

 

4.Ajax

Ajax即异步的javascript。在不全部加载某一个页面部的情况下,对页面进行局的刷新,ajax请求都在后台(在浏览器开发人员选项network可见)。

 

使用ajax提交时,以下两点很重要:

1)    首先分析出请求地址时需要携带的参数。
2)    视图函数处理完成之后,所返回的json的格式。

 

Ajax需要用到JQuery。注:图片,css文件,js文件都是静态文件。

(在Django用静态文件可参考 静态文件 。 更多关于设置和框架的资料,参考 静态文件解惑 和 静态文件指南。部署静态文件 介绍了如何在真实服务器上使用静态文件。

 

Ajax的流程

  1. 发起ajax请求:jquery发起
  2. 执行相应的视图函数进行处理,返回json内容
  3. 执行相应的回调函数。通过判断json内容,进行相应处理。

【Django 笔记】视图---URL路由、自定义错误页面、HttpRequest对象、Ajax、Cookie、session_第1张图片

 

例子:(在Django项目中)

test_ajax.html




    
    ajax
    {% load static %}
    
    
    



应用/urls.py


from django.urls import path,include
from booktest import views

urlpatterns = [
    # ...
    path('test_ajax', views.ajax_test, name='test_ajax'),  # 现实ajax页面
    path('ajax_handle', views.ajax_handle, name='ajax_handle'),  # ajax处理
]

视图views.py

from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse

# Create your views here.

#...省略


# /test_ajax
def ajax_test(request):
    '''显示ajax页面'''
    return render(request, 'booktest/test_ajax.html')


def ajax_handle(request):
    '''ajax请求处理'''
    # 返回的json数据 {'res': 1}
    return JsonResponse({'res': 1})  # 返回的字典会转换成Json数据

以上,运行服务器,访问http://127.0.0.1:8000/test_ajax,

  • 点击"ajax请求" 按钮,就会跳出返回的"1"。
  • 将那几个alert的注释打开,会发现只要发起请求,不等回调函数执行,代码就会直接往下走。这就是异步。
  • 设置'async'为 false,则为同步的Ajax请求

应用Ajax的场景很多,比如登录页面的校验

 

5.Cookie

Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。

Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码。典型应用:记住用户名,网站的广告推送。

Cookie的特点

  • Cookie以键值对的格式进行信息的存储。
  • Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问google.com时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到google.com写的Cookie信息。
  • 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
  • cookie是有过期时间的,如果不指定,默认关闭浏览器之后cookie就会过期

【Django 笔记】视图---URL路由、自定义错误页面、HttpRequest对象、Ajax、Cookie、session_第2张图片

 

在Django中实现Cookie的读写

设置cookie:需要一个HttpResponse类或其子类的对象(JsonResponse, HttpResponseRedirect),set_cookie 用于设置cookie。参考:HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None)

 

读取cookie:浏览器发送给服务器的cookie保存在request对象的 COOKIES属性( 见HttpRequest.COOKIES )。

例子:(注:运行后访问,在浏览器开发人员选项-->network可见)

# 1.文件views.py

# ...省略
# /set_cookie
def set_cookie(request):
    '''设置cookie信息'''
    response = HttpResponse('设置cookie')
    # 设置一个cookie信息,名字为num, 值为1
    response.set_cookie('num', value='1', max_age=14*24*3600)  # max_age,expires 都可以用来设置过期时间
    # response.set_cookie('num2', value='2')
    # response.set_cookie('num', value='1', expires=datetime.now()+timedelta(days=14))
    # 返回response
    return response

# /get_cookie
def get_cookie(request):
    '''获取cookie的信息'''
    # 取出cookie num的值
    num = request.COOKIES['num']
    return HttpResponse(num)



# 2.文件urls.py

#。。。省略
urlpatterns = [
    # ...
    path('set_cookie', views.set_cookie, name='set_cookie'),  # 设置cookie
    path('get_cookie', views.get_cookie, name='get_cookie'), # 获取cookie
]

 

 

6.session

对于敏感、重要的信息,建议要储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息。

Session就是在服务器端进行状态保持的方案。

session的特点

1) session是以键值对进行存储的。

2) session依赖于cookie。唯一的标识码保存在sessionid cookie中。

3) session有过期时间,如果不指定,默认两周就会过期。

【Django 笔记】视图---URL路由、自定义错误页面、HttpRequest对象、Ajax、Cookie、session_第3张图片

 

Django项目默认启用Session

在settings.py文件,中间件MIDDLEWARE_CLASSES中包含Session中间件:'django.contrib.sessions.middleware.SessionMiddleware'

 

session存储方式

可以存储在数据库、缓存、Redis等。在项目settings.py文件,设置SESSION_ENGINE项指定Session数据存储的方式。

1)存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式。

SESSION_ENGINE='django.contrib.sessions.backends.db'

2)存储在缓存中:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'

3)混合存储:优先从本机内存中存取,如果没有则从数据库中存取。

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

若存储在数据库中,需要在项INSTALLED_APPS中安装Session应用:'django.contrib.sessions' (默认)。

 

设置和获取session用:HttpRequest.session

  • 设置session:request.session[‘username’] = ‘smart’

  • 获取session:request.session['username']、request.session.get('键',默认值)、

  • 清除所有session,在存储中只删除值部分:request.session.clear()

  • 清除session数据,在存储中删除session的整条数据request.session.flush()

  • 删除session中的指定键及值,在存储中只删除某个键及对应的值:del request.session['键']

  • 设置会话的超时时间,如果没有指定过期时间则两个星期后过期:request.session.set_expiry(value)

    • 如果value是一个整数,会话将在value秒没有活动后过期。
    • 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期。
    • 如果value为None,那么会话永不过期。

# 1.文件views.py

# ...省略

# /set_session
def set_session(request):
    '''设置session'''
    request.session['username'] = 'smart'
    request.session['age'] = 18
    # request.session.set_expiry(5)
    return HttpResponse('set session')

# /get_session
def get_session(request):
    '''获取session'''
    username = request.session['username']
    age = request.session['age']
    return HttpResponse(username+':'+str(age))

# /clear_session
def clear_session(request):
    '''清除session信息'''
    # request.session.clear()  # 在存储中只删除值部分
    request.session.flush()  # 在存储中删除session的整条数据
    return HttpResponse('清除成功')



# 2.文件urls.py

#。。。省略
urlpatterns = [
    # ...
    path('set_session', views.set_session, name='set_session'),  # 设置session
    path('get_session', views.get_session, name='get_session'),  # 获取session
    path('clear_session', views.clear_session, name='clear_session'),  # 清除session
]

以上可在表django_session中查看前后变化。

 

cookie和session的应用场景

  • cookie:记住用户名。安全性要求不高。
  • session:涉及到安全性要求比较高的数据。用户登录状态、银行卡账户、密码等。

 

 

-----end-----

你可能感兴趣的:(Django)