第四节 视图层

一 三板斧问题

1.在视图函数中的函数跟普通函数不太一样:
	视图函数里的函数必须加request参数
	必须要有返回值,返回值必须是HttpResponse对象

2.django中使用的是局部的request
def index(request):
    pass

def func(request):
    pass

	以上函数没有返回值,因此会出现以下报错提醒:
	The view app01.views.index didn't return an HttpResponse object. It returned None instead.
	
	总结:
	"""
	所有的视图函数不能够没有返回值,并且返回值还必须是HttpResponse对象,
	其实我们三板斧(HttpResponse,render,redirect)本质上返回的都是HttpResponse对象
	------>可以通过追代码,去看三板斧的源码,就能得到以上的结婚
	"""

3.在flask中request使用的是全局的request
from ... import request
def index():
    pass

def func():
    pass
#所有的视图函数都使用全局的request对象,会不会乱套,不会乱套,如何做到不乱套?在源码中会显示出来

二 JsonResponse序列化

1.json格式的数据---->主要就是实现跨语言数据传输
	json格式的数据特点:双引号  eg:{"username":"kevin","age":18}


2.现在实现跨语言数据的传输都是json,在以前使用的是xml(xml就是自定义标签,类似于html)
	html中:<div></div>
	xml中:<username>jack</username>
	#微信支付朝微信的后盾发送参数的时候,使用的就是xml

3.之前json是如何序列化的
							在js中
	import json
	json.dumps     ------>JSON.stringify()
	json.loads	   ------->JSON.parse()  #对象

4.js如何获取一个对象
	方式一:
	obj = new Object() # {}得到一个空对象
	obj.username = 'kevin' # {'username':'kevin'}
	consolo.log(obj.username)#取值
	方式二:
	2.obj={} # 得到一个新对象

5.在Django中使用序列化
 方式一:按之间的经验我们会这样做:
	path('index/', views.index)

	def index(request):
		d ={'username':'kevin','age':18}
		import json
		d_json = json.dumps(d)  # 变成了字符串的形式
		return HttpResponse(d_json) # {"username": "kevin", "age": 18}

方式二:上面的不够方便,见以下优化代码
	from django.http import JsonResponse
	def index(request):
		d = {'username': 'kevin', 'age': 18}
		res = JsonResponse(d_json)
		print(res)  # <JsonResponse status_code=200, "application/json"> Json对象
		return JsonResponse(d_json) #序列化 {"username": "kevin", "age": 18}
	
	如果出现中文字符,如何序列化:
	方式一
	def index(request):
		d = {'username':'kevin哈喽','age':18}
		d_json=json.dumps(d,ensure_ascii=False)
		return HttpResponse(d_json)

	方式二:
	def index(request):
		d = {'username':'kevin哈喽','age':18}
		return JsonResponse(d,json_dumps_params={'ensure_ascii':False}) # json_dumps_params 详情见源代码
	
	---->但是方式二不适用非字典类型,所以见以下代码:
	In order to allow non-dict objects to be serialized set the safe parameter to False.l # 使用上面代码非字典类型发生的报错
	def index(request):
		l=[1,2,3,4]
		return JsonResponse(l,safe=False) #[1, 2, 3, 4]

三 form表单上传文件

3.1form表单上传文件的前提:

	1.请求方式必须是post
	2.enctype必须是form-data

3.2补充enctype 属性相关知识

enctype 属性可以用来改变表单数据的编码方式,常见的取值有:
1. 	application/x-www-form-urlencoded:默认值,将表单数据转换为 URL 编码的字符串。
2. 	multipart/form-data:将表单数据编码为多部分的 MIME 格式,通常用于上传文件。
3. 	text/plain:将表单数据以纯文本的形式进行编码,不进行任何转义。

3.3代码实现

path('ab_file/', views.ab_file)

<form action="" method="post" enctype="multipart/form-data">
    <input type="text" name="username">
    上传文件:<input type="file" name="myfile">
    <input type="submit" value="提交">
</form>

def ab_file(request):
    # 接收提交的文件数据
    # POST只能够获取到除文件数据post请求的普通数据,文件数据拿不到
    print(request.POST) # <QueryDict: {'username': ['rachel']}>
    # FILES接收的是文件数据
    print(request.FILES) # <MultiValueDict: {'myfile': [<InMemoryUploadedFile: 微信图片_20230713095129.jpg (image/jpeg)>]}>
    if request.method =='POST':
        file_obj=request.FILES.get('myfile') # 会得到一个文件对象
        # 上传图片文件
        with open(file_obj.name,'wb') as f:
            for line in file_obj:
                f.write(line)
    return render(request,'ab_file.html/')

四 CBV的书写和FBV的写法

# 目前写的都是FBV:function based view 基于函数的视图
# 在视图文件中书写类 CBV:class based view 基于类的视图

postman的官网地址:https://www.postman.com/downloads/
apizza的挂网地址:http://www.apizza.net/

    # CBV的路由	 后面必须为views.类.as_view()
    path('login/',views.Mylogin.as_view())
	
	# 所有的类必须继承django的view类
	from django.views import View

	class MyLogin(View):
		# 类里面的方法名字不能够随便写,目前只能写get post等
		# 访问这个地址必须是get请求方式
		def get(self, request):
			# get() takes 1 positional argument but 2 were given 函数后面必须加上request
			print("get")
			return HttpResponse("get")

		# 访问这个方法必须是psot请求方式
		# 通过form表单发送post请求
		# 除了form表单,我们还可以使用工具来模拟:postman,apizza
		def post(self,request):
			print("post")
			return HttpResponse("post")
   
 总结:
 """
	 1.所有的类必须继承django的view类
	 2.类里面的方法名字不能够随便写,目前只能写get post等
	 3. CBV的路由	 后面必须为views.类.as_view()  eg:path('login/',views.Mylogin.as_view())
	 4.CBV的访问地址以后就通过请求方式的不同来区分
 """

五 CBV的源码分析

# 我们第一次看Django的源码,面试题:你都看过Django的哪些源码,简单说说?
# CBV的源码、settings的源码、权限、频率、认证的、签发token的源码

1.看源码的步骤是先找到源码的入口
	CBV的入口---->路由中 path('login/', views.MyLogin.as_view()),
	其中 views.MyLogin.as_view() MyLogin类中没有as_view方法,就去父类View中找

2.点击as_view进源码
@classonlymethod
    def as_view(cls, **initkwargs):
        #注意这里的cls:MyLogin
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)
        return view # 返回内层函数的函数名,函数对象
    

3.path('login/', View.view),

4.当请求来的时候,开始匹配路由login,就会调用View.view()

5.dispatch先去对象里面找,再去产生这个对象的类里面找,再去父类(View)中找
        def view(request, *args, **kwargs):
            # self = MyLogin(**initkwargs)
            self = cls(**initkwargs)
            """
                self: MyLogin()
                self是Mylogin的对象
            """
            return self.dispatch(request, *args, **kwargs) # 这句话是最重要的,dispatch先去对象里面找,再去产生这个对象的类里面找,再去父类(View)中找
			
6.self.dispatch(request, *args, **kwargs) 

7.找到了View类里面的dispatch方法

8.
	def dispatch(self, request, *args, **kwargs):
        	# getattr: 反射
            # 反射
            # getattr setattr delattr hasattr
            # handler = getattr(self, 'get', self.http_method_not_allowed)
            # handler = getattr(self, 'post', self.http_method_not_allowed)
            # handler就是方法名,对象
            # hander = get
            # hander = post
            # hander = self.http_method_not_allowed
    #request.method:GET POST---->get post
    #http_method_names= http_method_names = ["get","post","put","patch","delete","head",
"options","trace",]
        if request.method.lower() in self.http_method_names:
        # handler就是方法名,对象
        # handler = get
        # handler = post
        # handler = self.http_method_not_allowed
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs) # get(request) post(request)

5.2如何让写的CBV类只支持get请求或者只支持post请求?

class MyLogin(View):
    http_method_names = ['get',]
    # 类里面的方法名字不能够随便写,目前只能写get post等
    # 访问这个地址必须是get请求方式
    def get(self, request):
        # get() takes 1 positional argument but 2 were given
        print("get")
        return HttpResponse("get")
"""
回顾内容
	类名可以调用哪些方法:
		1. 方法被@classmethod装饰器修饰的方法
			类名来调用类方法有什么特殊之处:
				会把类名自动当成第一个参数传递给方法的第一个形参cls
				对象调用方法把对象自己当成第一个参数传给方法的第一个形参self
			
		2. 被@staticmethod装饰器修饰的方法
"""

六 request对象的另外几个方法

request.GET
request.POST
request.FILES

request.path_info  #  /ab_request/ 
reqeust.path       #  /ab_request/ 
request.get_full_path() # /ab_request/  /ab_request/?username=kevin&age=11
request.body # 现在先不学,它能够接收浏览器发过来的二进制数据,BBS项目中学
posted @ 2023-08-01 22:04  瓜瓜不甜  阅读(8)  评论(0编辑  收藏  举报