四方显神

导航

Django开发笔记(四)四件套二:视图

这篇开始的学习需要借助postman,针对数据解耦开发。自行下载即可。

django的视图主要有2种,分别是函数视图类视图.现在刚开始学习django,我们先学习函数视图(FBV),后面再学习类视图[CBV].

视图函数里只有两块内容:

  • 请求对象request;
  • 响应对象HttpResponse、render、redirect。

请求来了是wsgi.py接收并封装了socket:

一、请求方式

GET POST PUT DELETE等

二、请求对象

request请求体有两种格式:

  • urlencoded形如: a=1&b=2&c=3   
  • json形如:  {"a":1,"b":2,"c":3}

发送POST请求时获取数据的方式:

request.body
request.POST # python只会把urlencoded这种格式的内容解析到request.POST里,不解析json格式的内容

request.POST拿到的urlencoded格式的请求体,返回的是:<QueryDict: {'user': ['bao'], 'pwd': ['1234']}> 

可以看到,这个字典键值对里的值,是个列表,但是当我用user = request.POST.get("user") 取的时候,取出来的是 bao ,并不是一个列表。那是因为Django用get方法去取的时候,取的是最后一个值。

所以如果应对一个键传多个值,要获取全部值,就不能用get方法了,就要用user = request.POST.getlist("XXX") 方法了。

发送GET请求时获取数据的方式:

request.GET

获取请求路径:

request.path # 只有路径
request.get_full_path() #包含get参数

这两者的区别:例如当我们的请求是http://127.0.0.1:8000/users?user=jin&pwd=123 的时候,两者的运行结果:

print(request.path) # /users
print(request.get_full_path()) # /users?user=jin&pwd=123

获取请求头数据:

request.META
request.META.get("HTTP_HOST") # 拿出请求头上的某个数据

 

完整views.py(可以不看,知道上面讲的方法就行):

from django.shortcuts import render,HttpResponse
from django.views.decorators.csrf import csrf_exempt

'''

GET / HTTP/1.1
...
请求体   格式有两种:  urlencoded: a=1&b=2&c=3    json:  {"a":1,"b":2,"c":3}

'''

@csrf_exempt
def index(request):

    # 获取请求方式
    print(request.method) #POST GET等

    # # POST请求获取请求体数据
    print(request.body)
    print(request.POST) # python只会把urlencoded这种格式的内容解析到request.POST里,不解析json格式的内容、
    user = request.POST.get("user") # 使用
    pwd = request.POST.get("pwd")
    print(user)

    # # GET请求获取请求体数据
    print(request.GET) # <QueryDict: {'user': ['jin'], 'pwd': ['123']}>

    # 获取请求路径:
    print(request.path) # /users
    print(request.get_full_path()) # /users?user=jin&pwd=123
    # 获取请求头
# print(request.META)
print(request.META.get("HTTP_HOST"))
    return HttpResponse("ok") def test(request): return HttpResponse("test successfully!")

 

这节我遇到了一个错误,我使用postman发送POST请求的时候报403 forbidden错,参考了博客:Django CSRF cookie not set.错误 - 蜗牛findbug - 博客园 (cnblogs.com)  ,代码里加上了红色框框部分,解决了这个问题:

from django.views.decorators.csrf import csrf_exempt
@csrf_exempt

这个问题是解决跨域请求,不建议使用这个注解绕过机制,我找了好久更好的解决方法也没有找到。

关于跨域问题可以参考:

Django Django中的@csrf_exempt是什么|极客教程 (geek-docs.com) 

一招彻底解决Django跨域请求问题_django转发请求-CSDN博客

我觉得应该是我postman没有配置好出现了这个问题,但是postman发送get请求就没有这个问题。暂时我还没有找到postman改哪里可以不这样。

2023.12.20更新:

这个问题还可以有另一种解决方案,就是settings.py中有个中间件,对post请求做了一个拦截,注掉就可以了:

三、响应对象

响应对象主要有三种形式:

  • HttpResponse()
  • render()
  • redirect()

1.HttpResponse

Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个 HttpRequest 对象传给视图函数。那么视图函数在处理完相关的逻辑后,也需要返回一个响应给浏览器。而这个响应,我们必须返回 HttpResponseBase 或者他的子类的对象。而 HttpResponse 则是 HttpResponseBase 用得最多的子类。

常用属性:

  • content:返回的内容。
  • status:返回的HTTP响应状态码。
  • content_type:返回的数据的MIME类型,默认为 text/html 。浏览器会根据这个属性,来显示数据。如果是 text/html ,那么就会解析这个字符串,如果 text/plain ,那么就会显示一个纯文本。
  • 设置响应头: response['X-Access-Token'] = 'xxxx' 。

 例如:

@csrf_exempt
def index(request):

    res= HttpResponse("ok")
    res["user"]="bao" # 自定义响应头
    return  res

效果就是响应头多加了这个user:

2.JsonResponse

用来对象 dump 成 json 字符串,然后返回将 json 字符串封装成 Response 对象返回给浏览器。并且他的 Content-Type 是 application/json 。示例代码如默认情况下 JsonResponse 只能对字典进行 dump ,如果想要对非字典的数据进行 dump ,那么需要给 JsonResponse 传递一个 safe=False 参数。

1)不使用JsonResponse

@csrf_exempt
def index(request):

    stu={"name":"李莲花","age":24}
    import json
    return HttpResponse(json.dumps(stu,ensure_ascii=False)) # 这样可以识别中文字符

此时的结果是:

 

2)使用JsonResponse(本例也是一个dump字典的例子,下面会有dump列表的例子,注意看区别

def index(request):
stu={"name":"李莲花","age":24} return JsonResponse(stu)

结果:

可以看出,它已经将json解析了,有自己的json格式了。因为JsonResponse会对我们有一个content_type的设置,源码如下:

 

 

3)使用JsonRespose序列化一个列表:

默认情况下 JsonResponse 只能对字典进行 dump ,如果想要对非字典的数据进行 dump ,那么需要给 JsonResponse 传递一个 safe=False 参数。

不加参数就会报错:

加了参数后的代码:

def index(request):
    books=[{"姓名":"钱钟书","age":34},{"姓名":"钱媛媛","age":5}]
    return JsonResponse(books,safe=False)

 

3.render对象

render我们第二篇用过,这个单词本身的意思就是渲染,当时我们用的是:render(request,"xx一个页面")

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

参数:

 /*
 request: 用于生成响应的请求对象。
 template_name:要使用的模板的完整名称,可选的参数
 context:添加到模板上下文的一个字典,
          默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
          */
render(request, template_name[, context])

实例:

views.py:

def index(request):
        remote_addr = request.META.get("REMOTE_ADDR")
        return render(request,"users/index.html", {"ip":remote_addr})

index.html:

<body>

    <h1>欢迎你,{{ip}} </h1>

</body>

最终效果:

后面会有一章节专门学模板语法,就是专门讲render的。

4.redirect

使用Django框架构建Python Web应用程序时,在某些时候必须将用户从一个URL重定向到另一个URL,通过redirect方法实现重定向。

参数可以是:

  • 一个绝对的或相对的URL, 将原封不动的作为重定向的位置.
  • 一个url的别名: 可以使用reverse来反向解析url

传递要重定向到的一个具体的网址。APPEND_SLASH的实现就是基于redirect。

传递要重定向到的一个具体的网址:

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

当然也可以是一个完整的网址:

def my_view(request):
    ...
    return redirect("http://www.baidu.com")

传递一个视图的名称:

def my_view(request):
    ...
    return redirect(reverse("url的别名")) 

重定向的时候发了两个请求:

 

用重定向做一个登陆页面的案例:

users/url.py:

from  django.urls import  path,re_path
from users.views import index,login,auth

urlpatterns = [
   path("",index),
   path("login/",login),
   path("auth/",auth)
]

views.py:

from django.shortcuts import render,HttpResponse,redirect
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def index(request):
        remote_addr = request.META.get("REMOTE_ADDR")
        return render(request,"users/index.html", {"ip":remote_addr})

@csrf_exempt
def login(request):
        return render(request,"users/login.html")

@csrf_exempt
def auth(request):
        # 获取数据
        # print("request.post:",request.POST)
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        # 模拟数据校验
        if user == "admin" and pwd =="123":
                return redirect("/users")
        else:
                msg = "用户名或密码错误"
                return render(request,"users/login.html", {"msg":msg}) # 如果返回的是静态页面,渲染一些新信息的时候可以这么玩
                # return redirect("/users/login")

users/login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="http://127.0.0.1:8000/users/auth/" method="post">
    用户名:<input name = user type="text">
    密 码:<input name = pwd type="password">
    <input type="submit"><span style="color: red">{{ msg }}</span>
</form>

</body>
</html>

为了帮助理解,对于这个案例的图:

 那么,其实返回静态页面的时候,是可以不用重定向的,也即就是下图框框里两种写法都行:(这里行是因为这里简单,就是一个静态页面)

 但是上面的users/那个是动态页面,要渲染,要取页面什么的,就建议使用重定向了。

 

这个案例还有一个小细节,就是users/login.html文件里的:

 这里绝对路径复杂,可以删掉,只留一个相对路径:(但前面的 / 一定要加,不然就不是相对路径了)

重定向之APPEND_SLASH

浏览器url请求的时候最后不加杠“/”,但点击回车后自动补了"/":

 

 这个小动作是Django做的,不是浏览器做的哦。

这个小动作里发生了两次请求,一次重定向:

可以打开浏览器页面的检查(F12)验证一下这个过程。

这个效果是由Django的配置文件settings.py设置的,默认是true。设置为FALSE就是关闭这个功能:

APPEND_SLASH=False

posted on 2023-12-06 20:57  szdbjooo  阅读(40)  评论(0)    收藏  举报