【一】关于HTTP请求的补充
#
"""request.POST请求必须是post请求且是urlencoded的编码格式的数据才能拿到数据"""
#1.http请求不同编码格式,请求体什么样子?重要
-urlencoded:在请求体中是--》b'id=1&name=llh'
-json:在请求体中是json--b'{"name":"lqz","age":19}'
-form-data: 随机字符串asdfasdf-------数据部分 随机字符串asdfasdfasdf-----文件部分
eg:
b'----------------------------876677566299917579045132\r\nContent-Disposition: form-data; name="id"\r\n\r\n1\r\n----------------------------876677566299917579045132\r\nContent-Disposition: form-data; name="myfile"; filename="1.txt"\r\nContent-Type: text/plain\r\n\r\n1\r\n----------------------------876677566299917579045132--\r\n'
#2.get请求能不能在请求体中携带数据?
-能,只能在request.body里取不能在request.POST里取他取不到东西
-但是一般都是post或put请求在请求体中带数据
#3.get请求和post请求的区别?
总结:
-1.request.POST请求必须是post请求且是urlencoded的编码格式的数据才能拿到数据
-2.request.GET:请求地址栏中url链接的参数?后面的:这些请求都能拿到get,post,delete,put
request.GET---><QueryDict: {'key': ['key', '99']}>
-类字典:取出key的值
-只取一个:request.GET.get('key')
-两个都取:request.GET.getlist('key')
-3.request.body:无论什么请求, 无论什么编码格式,都在里面
【二】新的Request对象和Response
2.1Request
#1.以后全是cbv,继承的是drf的APIView--->它也继承django的View及子类
#2.DRF提供了Response类,这是专门设计来生成HTTP响应的,并且可以与DRF的各种特性,继承APIView后,以后响应同意用drf的Response
#3.APIView中的request请求对象
-1.request请求对象:http请求的所有内容,都会在这个对象中
-2.继承APIView后的request对象和原来的request对象不是同一个
-原来是:<class 'django.core.handlers.wsgi.WSGIRequest'>
-继承之后是:<class 'rest_framework.request.Request'>
-3.但是用法与原来的request对象相同,都有如下方法而且,得到的结果一样
print(request.method)//GET
print(request.POST)//<QueryDict: {}>
print(request.GET)//<QueryDict: {}>
print(request.get_full_path())// /api/v3/index/
-4.有一样的肯定也有不一样升级的地方
-4.1request.body不同,原来的request对象可以直接取出请求中原生的请求体数据,位置在哪无所谓,但是现在新的一定要是写在是在其他request.的第一个要不然会报django.http.request.RawPostDataException: You cannot access body after reading from request's data stream)
"""如果之前已经有request.POST或request.PUT就会,由于数据流只能被读取一次,可能在POST取后,那个数据已经变了一种格式了"""
-4.2.在继承APIView的request对象中,可以利用request.data,无论哪种编码格式,请求体的数据,都在这里面
-urlencoded,form-data:是QueryDict的对象
form-data:<QueryDict: {'id': ['1'], 'myfile': [<InMemoryUploadedFile: 1.txt (text/plain)>]}>
urlencoded:<QueryDict: {'id': ['1'], 'name': ['llh']}>
-json:是普通字典对象{'detail': 'q.'}
-但是,都当字典用即可
request_data就是一个字典
-5.request.FILES新旧相同
-前端传的文件从这里取
新/旧:<MultiValueDict: {'myfile': [<InMemoryUploadedFile: 1.txt (text/plain)>]}>
-6.request.query_params # restful规范的过滤条件(就是问号后面)的查询参数
-request.GET
eg:<QueryDict: {'name': ['llh']}>
2.2Response
# 1.from rest_framework.response import Response
#2.怎么用?
-1 直接放字典,列表或字符串
Response('ok')这个ok是放在了响应体里了
#3.如何放状态码?Response('ok',status=200)
#4.如何放响应头?Response('ok',status=200,headers={k:v})
#5.总结
data=None # 响应体:可以传 字典,列表或字符串body
status=None# http响应 状态码--》drf封装了所有常量 HTTP_200_OK = 200
template_name=None# 忽略掉--》指定使用浏览器访问返回的模板,没写用默认模板,如果要用记得要去注册一下
headers=None # 响应头
exception=False# 异常
content_type=None # 响应编码格式,一般不动,都用json
【三】 序列化类介绍
# 序列化类的作用?
-前端传json格式字符串 给 后端 --》后端需要 保存到数据库---》反序列化
-后端从数据库查出来的 对象---》以json格式字符串的形式给前端--》序列化
-serializer就是为了完成上面的操作
序列化
反序列化
反序列化校验
【四】序列化类快速使用
4.1快速使用
"""
使用步骤:
1 定义一个类,继承Serializer
2 在类中写要序列化的字段:字段类,跟models中得一一对应
3 在视图类中使用三步走
# 1 查出对象
obj = Student.objects.filter(pk=pk).first()
# 2 序列化
serializer = StudentSerializer(instance=obj)
# 3 返回
return Response(serializer.data)
"""
1.view.py
class StudentView(APIView):
def get(self,request):
obj=Student.objects.all()
serializer=StudentSerializer(instance=obj,many=True)
return Response(serializer.data)
2.models.py
from django.db import models
# Create your models here.
class Student(models.Model):
name=models.CharField(max_length=30)
age=models.IntegerField()
gender=models.IntegerField(choices=((1,'男'),(2,'女'),(0,'未知')),default=1,)
3.serializers.py
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
id=serializers.IntegerField()
name=serializers.CharField()
age=serializers.IntegerField()
gender=serializers.IntegerField()
4.2常用字段类
# 1 记住--》跟models中得 model.字段类, 一一对应
# 2 具体有哪些--了解
BooleanField
NullBooleanField
CharField #
EmailField
RegexField
SlugField
URLField
UUIDField
IPAddressField
IntegerField #
FloatField
DecimalField
DateTimeField #
DateField #
TimeField #
ChoiceField
MultipleChoiceField
FileField
ImageField
# --------两个特殊的,后面讲,很重要----
ListField
DictField
# 3 大绝招:如果不知道models和Serializer如何对应
序列化类统一用 CharField
4.3常用字段参数
# 1 序列化的 字段类在实例化时,传参数
-作用是:为了反序列化校验用
# 2 有哪些字段参数--》了解
# 只针对于:CharField
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
# 只针对于:IntegerField
max_value 最小值
min_value 最大值
# 只针对于:DateTimeField
format:序列化时,显示的格式
DateTimeField(format='Y-m-d')
# 所有字段类都用
required:是否必填
default :反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
# 3 两个重点-先不讲
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
【五】反序列化保存
5.1新增
#1.view.py
def post(self,request):
print()
serializer=StudentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response({"code":201,"msg":serializer.errors})
#2.serializer
class StudentSerializer(serializers.Serializer):
id=serializers.IntegerField(required=False)
name=serializers.CharField(required=True)
age=serializers.IntegerField(required=True)
gender=serializers.IntegerField(required=False,default=0)
# 不重写会报错在baseSerializer有一个save方法--》里有update
# def create(self, validated_data):
# raise NotImplementedError('`create()` must be implemented.')
def create(self, validated_data):
student=Student.objects.create(**validated_data)
# if self.instance is not None:
# self.instance = self.update(self.instance, validated_data)
# assert self.instance is not None, (
# '`update()` did not return an object instance.'
# )必须要有返回值否则就断言报错
return student
#3.models.py
class Student(models.Model):
name=models.CharField(max_length=30)
age=models.IntegerField()
gender=models.IntegerField(choices=((1,'男'),(2,'女'),(0,'未知')))
5.2更新
#1.views.py
def put(self, request,book_id):
obj = Student.objects.filter(pk=book_id).first()
if obj:
serializer=StudentSerializer(instance=obj,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response({"code": 201, "msg": "修改失败"})
#2.serializer
def update(self, instance, validated_data):
print(instance)#是一个对象Student object (1)
print(validated_data)#是一个字典{'name': '阿1', 'age': 2, 'gender': 0}
for key in validated_data:
# key是一个字符串,字符串和对象就可以想到反射
setattr(instance,key,validated_data[key])
return instance
5.3关于修改和更新的源码
1.执行serializer.save()--->StudentSerializer类中没用--》所以去他的父类里面找Serializer--》还是没有--》去爷爷类找BaseSerializer--》发现有save()
2.观察save()
""" 发现1:他是通过判断self.instance有没有值来判断是更新还是修改
发现2:至于为什么一定要返回instance呢,因为最后一句是要返回的,然后如果不给self.instance值那么,就会报错"""
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.instance
3.观察update和create
"""发现1:update必须有两个形参,create是一个
发现2:如果不去重写实现update和create会主动抛出异常"""
def update(self, instance, validated_data):
raise NotImplementedError('`update()` must be implemented.')
def create(self, validated_data):
raise NotImplementedError('`create()` must be implemented.')
1.把学生的5个接口写完,使用序列化类
#1.views
from rest_framework.response import Response
from rest_framework.views import APIView
from app03.models import Student
from app03.serializer import StudentSerializer
# Create your views here.
class StudentView(APIView):
def get(self,request):
obj=Student.objects.all()
if obj:
serializer=StudentSerializer(instance=obj,many=True)
return Response(serializer.data)
return Response({"code": 201, "msg": "查询失败"})
def post(self,request):
serializer=StudentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response({"code":201,"msg":serializer.errors})
class StudentDetailView(APIView):
def get(self, request,book_id):
obj=Student.objects.filter(pk=book_id).first()
if obj:
serializer=StudentSerializer(instance=obj,many=False)
return Response(serializer.data)
return Response({"code": 201, "msg": "查询失败"})
def put(self, request,book_id):
obj = Student.objects.filter(pk=book_id).first()
if obj:
serializer=StudentSerializer(instance=obj,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response({"code": 201, "msg": "修改失败"})
def delete(self, request,book_id):
obj = Student.objects.filter(pk=book_id).first()
if obj:
Student.objects.filter(pk=book_id).delete()
return Response(status=200)
return Response({"code": 201, "msg": "查询失败"})
#2.models
from django.db import models
# Create your models here.
class Student(models.Model):
name=models.CharField(max_length=30)
age=models.IntegerField()
gender=models.IntegerField(choices=((1,'男'),(2,'女'),(0,'未知')))
#3.serializer.py
from rest_framework import serializers
from app03.models import Student
class StudentSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(required=True)
age = serializers.IntegerField(required=True)
gender = serializers.IntegerField(required=False, default=0)
# 不重写会报错在baseSerializer有一个save方法--》里有update
# def create(self, validated_data):
# raise NotImplementedError('`create()` must be implemented.')
def create(self, validated_data):
student = Student.objects.create(**validated_data)
# if self.instance is not None:
# self.instance = self.update(self.instance, validated_data)
# assert self.instance is not None, (
# '`update()` did not return an object instance.'
# )必须要有返回值否则就断言报错
return student
def update(self, instance, validated_data):
print(instance)#是一个对象Student object (1)
print(validated_data)#是一个字典{'name': '阿1', 'age': 2, 'gender': 0}
for key in validated_data:
# key是一个字符串,字符串和对象就可以想到反射
setattr(instance,key,validated_data[key])
return instance
"""注意要汉化错误信息在setting里改
LANGUAGE_CODE = 'zh-hans'
# 时区 UTC 国际时区
# 本地时区 中国时区在亚洲上海
# Asia/Shanghai
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
"""
2.编写一个装饰器,装在fbv上,让原生django的request对象,具备跟drf的request一样的data功能
from functools import wraps
# Create your views here.
# 装饰器
def outter(func):
@wraps(func)
def inner(request,*args,**kwargs):
data=json.loads(request.body)
# print(data)
# print(type(data))
# 因为request是对象,对象和字符串
setattr(request,'data',data)
return func(request,*args,**kwargs)
return inner
@outter
def index(request):
print(request.data)
obj = Books2.objects.all()
books_list = {"code": 100, "msg": "查询成功",
"results": [{"id": book.id, "name": book.name, "price": book.price} for book in obj]}
# 因为JsonResponse只能发送字典的数据,我们要发的是一个列表,所以
return JsonResponse(books_list, safe=False)
3.研究一下:QueryDict
from django.http import QueryDict
QueryDict的父亲是MultiValueDict,爷爷是dict,所以他是具备dict的所有功能,但是他也重写了一些方法
1.它能够处理一个键对应多个值的情况,这在HTML表单中很常见,例如多选框(<select multiple>)或具有相同名称的多个输入框
2.QueryDict:提供了一些特定的方法来处理表单数据和URL查询参数,如get()(获取单个值,如果键有多个值则获取最后一个值)、getlist()(获取键对应的所有值列表)等。
3.getlist()--》是他父类MultiValueDict的方法
用于获取与给定键相关联的所有值的列表
def _getlist(self, key, default=None, force_list=False):
"""
Return a list of values for the key.
Used internally to manipulate values list. If force_list is True,
return a new copy of values.
"""
try:
values = super().__getitem__(key)
except KeyError:
if default is None:
return []
return default
else:
if force_list:
values = list(values) if values is not None else None
return values