一 三板斧问题
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]
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项目中学