一、路由层(URLconf)
1.1 路由层简单配置
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。
urlpatterns = [ url(r'^admin/$', admin.site.urls), 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), ]
注意:
- 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是
^articles
而不是^/articles
。 - 每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义
[root@node10 mysite]# vim urls.py
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('articles/2019/', views.articles_2019), ]
编辑view.py
from django.shortcuts import render,HttpResponse # Create your views here. def articles_2019(request): print("articles_2019") return HttpResponse("articles_2019")
访问http://192.168.132.140:8888/articles/2019/
修改
[root@node10 mysite]# vim urls.p from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #path('articles/2019/', views.articles_2019), re_path(r'articles/([0-9]{4})/$', views.articles_year), ] [root@node10 mysite]# vim ../app01/views.py def articles_year(request): #这里只指定一个参数 print("articles_2019") return HttpResponse("articles_2019")
访问http://192.168.132.140:8888/articles/2019/
添加一个参数year
[root@node10 mysite]# vim ../app01/views.py
from django.shortcuts import render,HttpResponse def articles_year(request,year): #无名分组,按照微信hi传参 print("articles_%s" %year) return HttpResponse("articles_%s" %year)
访问http://192.168.132.140:8888/articles/2019/
访问http://192.168.132.140:8888/articles/2018/
访问http://192.168.132.140:8888/articles/2001/
1.2 有名分组
上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。
在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern)
,其中name
是组的名称,pattern
是要匹配的模式。
下面是以上URLconf 使用命名组的重写:
[root@node10 mysite]# vim urls.py
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #path('articles/2019/', views.articles_2019), re_path(r'articles/(?P<year>[0-9]{4})/$', views.articles_year), #有名分组,按照关键字传参匹配 ]
访问http://192.168.132.140:8888/articles/2008/
有名分组和无名分组,一个参数不能看出区别,添加两个参数后
[root@node10 mysite]# vim urls.py from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #path('articles/2019/', views.articles_2019), re_path(r'articles/([0-9]{4})/([0-9]{2})/$', views.articles_y_m), ] [root@node10 mysite]# vim ../app01/views.py from django.shortcuts import render,HttpResponse def articles_y_m(request,month,year): return HttpResponse("%s---%s" % (year,month))
访问http://192.168.132.140:8888/articles/2008/12/
只和位置相关
使用有名分组
from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #path('articles/2019/', views.articles_2019), re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m), ]
[root@node10 mysite]# vim urls.py
访问http://192.168.132.140:8888/articles/2008/12/
1.3 路由分发
在app01下创建一个新的文件
from django.urls import path,re_path from . import views urlpatterns = [ path("test/",views.test1), ]
注册这个路由
[root@node10 mysite]# vi urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path("app01/",include("app01.urls")), ]
编辑views.py
[root@node10 mysite]# cat ../app01/views.py
from django.shortcuts import render,HttpResponse # Create your views here. def test1(request): return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/
再次创建一个app02
[root@node10 mysite]# cd ../
[root@node10 mysite]# python3 manage.py startapp app02
[root@node10 mysite]# vi mysite/settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'app02.apps.App02Config', ]
[root@node10 mysite]# vim app02/urls.py
from django.urls import path,re_path from app02 import views urlpatterns = [ path("test02/",views.test02), ]
[root@node10 mysite]# vim app02/views.py
from django.shortcuts import render,HttpResponse # Create your views here. def test02(request): return HttpResponse("this is app02's test function")
添加路由
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #path('articles/2019/', views.articles_2019), #re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m), path("app01/",include("app01.urls")), path("app02/",include("app02.urls")), ]
访问http://192.168.132.140:8888/app02/test02/
1.4 反向解析
在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
- 在模板中:使用url 模板标签。
- 在Python 代码中:使用from django.urls import reverse()函数
使用test1测试
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login,name="Login"), #path('articles/2019/', views.articles_2019), #re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m), path("app01/",include("app01.urls")), #path("app02/",include("app02.urls")), ]
[root@node10 mysite]# vim app01/views.py
from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def test1(request): print(reverse("test1")) return HttpResponse("test1 view")
[root@node10 mysite]# vim app01/urls.py
from django.urls import path,re_path from . import views urlpatterns = [ path("test/",views.test1,name="test1"), ]
访问http://192.168.132.140:8888/app01/test/,查看调试结果
/app01/test/
[02/Apr/2020 03:42:24] "GET /app01/test/ HTTP/1.1" 200 10
使用html反向解析
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login,name="Login"), ]
[root@node10 mysite]# vim templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</script>
</head>
<body>
<h3>用户登录</h3>
<form action="{% url 'Login' %}" method="post">
<p>用户名:<input type="text" name="user"></p>
<p>密 码:<input type="password" name="pwd"></p>
<input type="submit">
</form>
<script>
</script>
</body>
</html>
[root@node10 mysite]# vim app01/views.py
from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def login(request): print(request.method) if request.method == "GET": return render(request,"login.html") else: #获取login.html获取到的user和pwd,这两个都是key user = request.POST.get("user") pwd = request.POST.get("pwd") print(user,pwd) if user == "darren" and pwd == "123456": return HttpResponse("登录成功") else:
访问http://192.168.132.140:8888/login/
调试结果输出
GET
[02/Apr/2020 03:27:35] "GET /login/ HTTP/1.1" 200 352
python反向带有参数,无名传参
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login,name="Login"), #path('articles/2019/', views.articles_2019), re_path(r'articles/([0-9]{4})/([0-9]{2})/$', views.articles_y_m,name="test11"), #re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m,name="test11"), path("app01/",include("app01.urls")), #path("app02/",include("app02.urls")), ]
[root@node10 mysite]# vim app01/views.py
from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def articles_y_m(request,year,month): print(reverse("test11",args=("%s" %year,"%s" %month))) return HttpResponse("%s----%s" %(year,month))
访问http://192.168.132.140:8888/articles/2018/11/
访问http://192.168.132.140:8888/articles/2019/12/
调试输出
[02/Apr/2020 04:13:20] "GET /articles/2018/11 HTTP/1.1" 301 0 /articles/2018/11/ [02/Apr/2020 04:13:20] "GET /articles/2018/11/ HTTP/1.1" 200 10 [02/Apr/2020 04:13:49] "GET /articles/2019/12 HTTP/1.1" 301 0 /articles/2019/12/ [02/Apr/2020 04:13:49] "GET /articles/2019/12/ HTTP/1.1" 200 10
python反向带有参数,有名传参
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login,name="Login"), #path('articles/2019/', views.articles_2019), #re_path(r'articles/([0-9]{4})/([0-9]{2})/$', views.articles_y_m,name="test11"), re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m,name="test11"), path("app01/",include("app01.urls")), #path("app02/",include("app02.urls")), ]
[root@node10 mysite]# vim app01/views.py
from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def articles_y_m(request,year,month): print(reverse("test11",kwargs={"year":"%s" %year,"month":"%s" %month})) return HttpResponse("%s----%s" %(year,month))
html带参反向解析,无名传参
[root@node10 mysite]# vim mysite/urls.py from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path(r'login/([0-9]{4})/([0-9]{2})/$', views.login, name="Login"), #path('articles/2019/', views.articles_2019), #re_path(r'articles/([0-9]{4})/([0-9]{2})/$', views.articles_y_m,name="test11"), re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m,name="test11"), path("app01/",include("app01.urls")), #path("app02/",include("app02.urls")), ] [root@node10 mysite]# vim app01/views.py from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def login(request,year,month): print(request.method) if request.method == "GET": return render(request,"login.html") else: #获取login.html获取到的user和pwd,这两个都是key user = request.POST.get("user") pwd = request.POST.get("pwd") print(user,pwd) if user == "darren" and pwd == "123456": return HttpResponse("登录成功") else: return render(request,"login.html") root@node10 mysite]# vim templates/login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </script> </head> <body> <h3>用户登录</h3> <form action="{% url 'Login' 2019 12 %}" method="post"> <p>用户名:<input type="text" name="user"></p> <p>密 码:<input type="password" name="pwd"></p> <input type="submit"> </form> <script> </script> </body> </html>
访问http://192.168.132.140:8888/login/2018/12/
html带参反向解析,有名传参
[root@node10 mysite]# vim mysite/urls.py from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #re_path(r'login/([0-9]{4})/([0-9]{2})/$', views.login, name="Login"), re_path(r'login/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.login, name="Login"), #path('articles/2019/', views.articles_2019), #re_path(r'articles/([0-9]{4})/([0-9]{2})/$', views.articles_y_m,name="test11"), re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m,name="test11"), path("app01/",include("app01.urls")), #path("app02/",include("app02.urls")), ] [root@node10 mysite]# vim templates/login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </script> </head> <body> <h3>用户登录</h3> <form action="{% url 'Login' year=2009 month=12 %}" method="post"> <p>用户名:<input type="text" name="user"></p> <p>密 码:<input type="password" name="pwd"></p> <input type="submit"> </form> <script> </script> </body> </html>
访问http://192.168.132.140:8888/login/2018/12/
1.5 名称空间
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
当不同app,那么重名时,返回值发生覆盖
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path(r'login111/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.login, name="Login"), re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m,name="test11"), path("app01/",include("app01.urls")), path("app02/",include("app02.urls")), ]
app01配置
[root@node10 mysite]# vim app01/urls.py
from django.urls import path,re_path from . import views urlpatterns = [ path("test/",views.test1,name="test1"), ]
[root@node10 mysite]# vim app01/views.py
from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def login(request,year,month): print(request.method) if request.method == "GET": return render(request,"login.html") else: #获取login.html获取到的user和pwd,这两个都是key user = request.POST.get("user") pwd = request.POST.get("pwd") print(user,pwd) if user == "darren" and pwd == "123456": return HttpResponse("登录成功") else: return render(request,"login.html") def articles_y_m(request,year,month): print(reverse("test11",kwargs={"year":"%s" %year,"month":"%s" %month})) return HttpResponse("%s----%s" %(year,month)) def test1(request): print(reverse("test1")) return HttpResponse("test1 view")
app02取相同name
[root@node10 mysite]# vim app02/urls.py
from django.urls import path,re_path from app02 import views urlpatterns = [ path("test02/",views.test02, name="test1"), ]
访问http://192.168.132.140:8888/app01/test/
查看调试返回
/app02/test02/
[02/Apr/2020 06:33:49] "GET /app01/test/ HTTP/1.1" 200 10
添加命名空间
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), #re_path(r'login/([0-9]{4})/([0-9]{2})/$', views.login, name="Login"), re_path(r'login111/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.login, name="Login"), #path('articles/2019/', views.articles_2019), #re_path(r'articles/([0-9]{4})/([0-9]{2})/$', views.articles_y_m,name="test11"), re_path(r'articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.articles_y_m,name="test11"), #path("app01/",include("app01.urls")), #path("app02/",include("app02.urls")), #名称空间 path("app01/",include(("app01.urls","app01"))), path("app02/",include(("app02.urls","app02"))), ]
[root@node10 mysite]# vim app01/views.py
from django.urls import path,re_path from . import views urlpatterns = [ path("test/",views.test1,name="test1"), ]
访问http://192.168.132.140:8888/app01/test/,调试返回结果
/app01/test/
[02/Apr/2020 06:35:45] "GET /app01/test/ HTTP/1.1" 200 10
二 视图层
2.1 介绍
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。
下面是一个返回当前日期和时间作为HTML文档的视图:
from django.shortcuts import render, HttpResponse, HttpResponseRedirect, redirect import datetime def current_datetime(request): now = datetime.datetime.now() html = "<h3>现在时刻: now %s</h3>" % now return HttpResponse(html)
代码分析
- 首先,我们从 django.shortcuts模块导入了HttpResponse类,以及Python的datetime库。
- 接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request
- 注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。
- 这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。
视图层需要熟练掌握两个对象:请求对象(request)和响应对象(HttpResponse)
2.2 HttpRequest对象
request属性,django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。 除了特殊说明的之外,其他均为只读的。
1.HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
[root@node10 mysite]# vim app01/views.py
def test1(request): #print(reverse("app01:test1")) print(request.GET) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/,调试输出
<QueryDict: {}>
[02/Apr/2020 07:08:08] "GET /app01/test/ HTTP/1.1" 200 10
访问http://192.168.132.140:8888/app01/test/?name=darren&age=18,调试输出
<QueryDict: {'name': ['darren'], 'age': ['18']}>
[02/Apr/2020 07:10:15] "GET /app01/test/?name=darren&age=18 HTTP/1.1" 200 10
取出name值
def test1(request): #print(reverse("app01:test1")) print(request.GET) print(request.GET.get("name")) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/?name=darren&age=18,调试输出
<QueryDict: {'name': ['darren'], 'age': ['18']}>
darren
[02/Apr/2020 07:27:21] "GET /app01/test/?name=darren&age=18 HTTP/1.1" 200 10
当有多个值时使用 print(request.GET.get("hobby"))
2.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
request.POST.getlist("hobby")
3.HttpRequest.body,原生的请求体的内容
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
[root@node10 mysite]# cat app01/views.py
def test1(request): #print(reverse("app01:test1")) print(request.body) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/?name=darren&age=18,调试输出
b''
[02/Apr/2020 07:32:49] "GET /app01/test/?name=darren&age=18 HTTP/1.1" 200 10
GET请求没有请求体
使用login访问
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), ]
[root@node10 mysite]# vim app01/views.py
def login(request): print(request.method) if request.method == "GET": return render(request,"login.html") else: print(request.body) #获取login.html获取到的user和pwd,这两个都是key user = request.POST.get("user") pwd = request.POST.get("pwd") print(user,pwd) if user == "darren" and pwd == "123456": return HttpResponse("登录成功") else: return render(request,"login.html")
[root@node10 mysite]# vim templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </script> </head> <body> <h3>用户登录</h3> <form action="" method="post"> <p>用户名:<input type="text" name="user"></p> <p>密 码:<input type="password" name="pwd"></p> <input type="submit"> </form> <script> </script> </body> </html>
访问http://192.168.132.140:8888/login
点击登录,调试输出
POST b'user=darren&pwd=123456' darren 123456 [02/Apr/2020 07:39:21] "POST /login/ HTTP/1.1" 200 12
4.HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
[root@node10 mysite]# vim app01/views.py
def test1(request): #print(reverse("app01:test1")) print(request.path) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/调试输出
/app01/test/
[02/Apr/2020 07:44:15] "GET /app01/test/ HTTP/1.1" 200 10
5.HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
[root@node10 mysite]# vim app01/views.py
def test1(request): #print(reverse("app01:test1")) print(request.method) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/调试输出
GET
[02/Apr/2020 07:46:06] "GET /app01/test/ HTTP/1.1" 200 10
6.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
7.HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。 CONTENT_TYPE —— 请求的正文的MIME 类型。 HTTP_ACCEPT —— 响应可接收的Content-Type。 HTTP_ACCEPT_ENCODING —— 响应可接收的编码。 HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。 HTTP_HOST —— 客服端发送的HTTP Host 头部。 HTTP_REFERER —— Referring 页面。 HTTP_USER_AGENT —— 客户端的user-agent 字符串。 QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。 REMOTE_ADDR —— 客户端的IP 地址。 REMOTE_HOST —— 客户端的主机名。 REMOTE_USER —— 服务器认证后的用户。 REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。 SERVER_NAME —— 服务器的主机名。 SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
8.HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
9.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
10.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
完整的细节参见会话的文档。
11.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
例如:
if request.user.is_authenticated(): # Do something for logged-in users. else: # Do something for anonymous users.
user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
2.3 request常用方法
1.HttpRequest.get_full_path()
返回 path,如果可以将加上查询字符串。
例如:"/music/bands/the_beatles/?print=true"
def test1(request): #print(reverse("app01:test1")) print(request.get_full_path()) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/?name=darren&age=18,调试输出
/app01/test/?name=darren&age=18 [02/Apr/2020 07:55:54] "GET /app01/test/?name=darren&age=18 HTTP/1.1" 200 10
2.HttpRequest.is_ajax()
- 如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
- 大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
- 如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
def test1(request): #print(reverse("app01:test1")) print(request.is_ajax()) return HttpResponse("test1 view")
访问http://192.168.132.140:8888/app01/test/?name=darren&age=18,调试输出
False
[02/Apr/2020 07:59:33] "GET /app01/test/?name=darren&age=18 HTTP/1.1" 200 10
2.4 HttpResponse对象
响应对象主要有三种形式(响应三剑客):
- HttpResponse()
- render()
- redirect()
HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接很简单
render方法
render(request, template_name[, context])
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
参数:
- request: 用于生成响应的请求对象。
- template_name:要使用的模板的完整名称,可选的参数
- context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
- render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。
[root@node10 mysite]# vim mysite/urls.py
from django.contrib import admin from django.urls import path,re_path,include from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login,name="Login"), ]
[root@node10 mysite]# vim app01/views.py
from django.shortcuts import render,HttpResponse,redirect from django.urls import reverse # Create your views here. def login(request): print(request.method) if request.method == "GET": return render(request,"login.html") else: print(request.body) #获取login.html获取到的user和pwd,这两个都是key user = request.POST.get("user") pwd = request.POST.get("pwd") print(user,pwd) if user == "darren" and pwd == "123456": return HttpResponse("登录成功") #这里是HttpResponse else: #return render(request,"login.html") #这里是render return redirect(reverse("Login")) #这里是用的是redict
访问http://192.168.132.140:8888/login/
点击提交后,依然是登录页面,调试输出
b'user=ning&pwd=123456' ning 123456 [02/Apr/2020 08:13:02] "POST /login/ HTTP/1.1" 302 0 GET [02/Apr/2020 08:13:02] "GET /login/ HTTP/1.1" 200 345
2.5 响应码3.1和302
2.5.1 301和302的区别
301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。
他们的不同在于:
- 301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;
- 302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301
2.5.2 重定向原因
- 网站调整(如改变网页目录结构);
- 网页被移到一个新地址;
- 网页扩展名改变(如应用需要把.php改成.Html或.shtml)。
这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。