作业:
# 原生的django中request中是没有data的,但是通过下面的这个装饰器就能实现通过点data也能获取到数据
def wrapper(func):
# 通过装饰器做装饰视图的,以后都会有request
def inner(request,*args,**kwargs):
'''
想要通过这个装饰器来使test功能也能从data里面拿到数据
1.创造一个新的request
2.如果是urlencoded,form-data 点request.POST,就有值
3.如果request.POST 没有值,就是竞赛你格式
'''
try:
request.data=json.loads(request.body) # 这里表示的就是叫你格式的编码
except Exception as e:
request.data=request.POST
res=func(request,*args,**kwargs)
return res
return inner
@wrapper
def test(request):
print(request.POST)
print(request.data)
return HttpResponse('实验成功')
总结:前端提交数据的编码格式
- urlencoded :
- name=lqz&age=19&price=999 放在了请求体中
- form-data:
- 分数据部分和文件部分
- mdata: 分数据部分和文件部分
文件部分是一堆二进制码 '------585520151165741599946333\r\n - form-datat name="name"\r\n\r\nlqz\r\
- json格式:
序列化常用字段和字段参数
序列化类
字段类 CharFiled,
字段属性 max_length=
序列化类有字段类,字段类能传属性,序列化类也能写属性
【models.CharField(max_length=32)】
1.常用字段类
1. BooleanField BooleanField()
2. NullBooleanField NullBooleanField()
3. CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
4. EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
5. RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
6. SlugField SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
7. URLField URLField(max_length=200, min_length=None, allow_blank=False)
8. UUIDField UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
9. IPAddressField IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
10. IntegerField IntegerField(max_value=None, min_value=None)
11. FloatField FloatField(max_value=None, min_value=None)
12. DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
13. DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
14. DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
15. TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
16. DurationField DurationField()
17. ChoiceField ChoiceField(choices) choices与Django的用法相同
18. MultipleChoiceField MultipleChoiceField(choices)
19. FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
20. ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)
#最常用的:CharField IntegerField DecimalField DateTimeField BooleanField
ListField
DictField
2.常用字段参数
# CharFiled 极其子类的(EmailFiled) 反序列化的校验,字段都是有自己的规则的
max_length 最大长度
min_length 最小长度
allow_blank 是否允许为空
trim_withespace 是否截断空白字符
# IntegerFiled
max_value 最大值
min_value 最小值
# 所有字段类中都有的属性
required 表明该字段在反序列化时必须输入,默认是True
default 反序列化时设置默认值
zllow_null 表明该字段是否允许传入None,默认是False
- 下面的属性使用的不多
error_messages 包含错误编码与错误信息的字典
label 用于HTML展示API页面时,显示字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
# 重要
read_only 表明该字段仅用于序列化输出,默认是False
write_only 表明该字段仅用于反序列化输入,默认值False
# 反序列化校验流程
1.先执行字段自己的校验规则,(最大长度,最小长度,是否为空,。。。。)
2.validators=[def(方法)],单独给某个字段加校验规则
name=serializers.CharField(validators=[方法,])
3.局部钩子校验
4.全局钩子校验
3.序列化使用---source(了解)
代码如下:
# 创建关联表
class Book(models.Model):
"""'''图书表'''"""
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
# 图书和出版社是一对多关系
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
# 图书和作者是多对多的关系
authors = models.ManyToManyField(to='Author')
class Publish(models.Model):
"""'''出版社表'''"""
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
"""'''作者表'''"""
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11)
4.序列化制定字段名字
class BookSerializer(serializers.Serializer):
# 定制专门的字段名 字段参数
name1=serializers.CharField(max_length=8,source='name')
price1=serializers.CharField(source='price')
"""
source :如果是自由字段就直接写
关联字段就直接点
多对多关联字段不能使用source
"""
publish=serializers.CharField(source='publish.name')
# 多对多关联字段不能使用source
authors=serializers.CharField(source='authors.all')
一对多关联字段除了上面的这种还能在模型层中Publish中直接:
# 直接在这里指定publish的名字
def __str__(self):
return self.name
注意事项:
使用source定制字段名不能和定制的的字段名重复,否则就会报错
ps:字段名的定制是为了提高数据库的安全性所设计的(字段名)
一对多,多对多序列化定制字段名
SerializerMethodField定制
# 显示形式
一对多显示的是字典
多对多显示是列表套字典
### 高级序列化
class BookSerializer(serializers.Serializer):
# 定制专门的字段名 字段参数
name1=serializers.CharField(max_length=8,source='name')
price1=serializers.CharField(source='price')
# 定制返回格式方式一
publish=serializers.SerializerMethodField()
# 使用这个属性必须要配合下面的这个方法
"""在这里return的是什么数据展示的就是什么数据,而且get后面跟的必须和字段名一样"""
def get_publish(self,obj):
return {'name':obj.publish.name,'addr':obj.publish.addr}
author_list=serializers.SerializerMethodField()
def get_author_list(self,obj):
l1=[]
for author in obj.authors.all():
l1.append({'name':author.name,'phone':author.phone})
return l1
方法二:
在模型表中定制
class Book(models.Model):
"""'''图书表'''"""
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
# 图书和出版社是一对多关系
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
# 图书和作者是多对多的关系
authors = models.ManyToManyField(to='Author')
# 把方法包装成数据属性 @property加不加都可以
@property
def publish_detail(self):
return{'name':self.publish.name,'addr':self.publish.addr}
@property
def author_list(self):
l1 = []
# for author in obj.authors.all():
# l1.append({'name':author.name,'phone':author.phone})
# return l1
return [{"name":author.name, "phone":author.phone} for author in self.authors.all() ]
# 序列化类
### 模型表中定制字段
class BookSerializer(serializers.Serializer):
# 定制专门的字段名 字段参数
name1=serializers.CharField(max_length=8,source='name')
price1=serializers.CharField(source='price')
# 定制返回格式方式一
publish_detail=serializers.DictField()
author_list=serializers.ListField()
多表关联反序列化保存
新增图书接口
# 新增一个图书接口
-{name:水浒传,price:88,publish:(下拉选择出版社),author:[1,2]}
代码如下
# 视图层
class BookView(APIView):
def post(self,request):
ser=BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'添加成功'})
else:
return Response({'code':101,'msg':ser.errors})
# 序列化类
class BookSerializer(serializers.Serializer):
# 这个字段既能序列化也能返序列化,既能读也能写
name = serializers.CharField(max_length=8)
price = serializers.CharField()
# 只能做序列化功能 只能读 read_only
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 只能用来做反序列化功能, 只能写 write_only
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
# 添加功能
"""新增数据必须要重写create方法"""
def create(self, validated_data):
"""
validated_data: 是新增的数据
"""
# 新增一本图书
book = Book.objects.create(name=validated_data.get('name'),
price=validated_data.get('price'),
publish_id=validated_data.get('publish')
)
# 作者也需要关联字段 多读点关联
book.authors.add(*validated_data.get('authors'))
return book
修改图书接口
代码:
# 序列化类
class BookSerializer(serializers.Serializer):
# 这个字段既能序列化也能返序列化,既能读也能写
name = serializers.CharField(max_length=8)
price = serializers.CharField()
# 只能做序列化功能 只能读 read_only
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 只能用来做反序列化功能, 只能写 write_only
publish = serializers.CharField(write_only=True)
authors = serializers.ListField(write_only=True)
# 重写修改方法
def update(self, instance, validate_data):
instance.name = validate_data.get('name')
instance.price = validate_data.get('price')
instance.publish_id = validate_data.get('publish')
# 因为原来的数据流式一个列表,而两个列表相加数据就会重复
authors = validate_data.get('authors')
# 先将原先的authors里面的数据清空
instance.authors.clear()
# 再将数据添加进去
instance.authors.add(*authors)
instance.save()
return instance
# 视图类
class BookViews(APIView):
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(data=request.data, instance=book)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功'})
else:
return Response({'code': 101, 'msg': ser.errors})
#路由添加
urlpatterns = [ path('books/<int:pk>/',views.BookViews.as_view())
]
小结:
-
关于read_only 和write_only 可以分别写在序列化和反序列化两个类中
-
在序列化和反序列化的时候一定要用read_only和write_only来控制
-
中文显示提示
-
ANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai USE_TZ = False
-
反序列化字段校验其他
校验的数据一共有四层:
-1.字段类自己的校验规则
name = serializers.CharField(max_length=8,error_messages={})
-2.validators=[def(方法)],单独给某个字段加校验规则
name=serializers.CharField(validators=[方法,])
-3.局部钩子校验
-4.全局钩子校验
ModelSerializer使用
ModelSerializer 是继承了serializer,添加很多的功能,完成很多的操作
- 跟表模型是强关联,只能是使用的是哪个表,就只能哪个表用这里面的功能
- 不需要写create和update
使用方法
class BookSerializer(serializers.ModelSerializer):
# 和表建立关系
class Meta:
model = Book # 序列化类和表建立了关系
# fields = '__all__' # 序列化所有的数据
"""
在Meta中写了__all__就相当于是复制了表模型类中的所有字段,放在这里
做了一个映射
"""
# 下面重写的数据一定要到这里注册,否则可能会报错
fields=['name','price','publish','author_list','publish_detail','authors']
# 单独给name定制反序列化的校验规则 给字段添加属性 方式一
extra_kwargs = {'name': {'max_length': 8},
'publish':{'write_only':True},
'authors':{'write_only':True},
'publish_detail':{'read_only':True},
'author_list':{'read_only':True}
}
# 单独给name定制校验规则 重写name字段 方法二 【一定要写在Meta的外面】优先使用这种方法
# name = serializers.CharField(max_length=7)
# # 把这个功能序列化写成和之前一模一样 序列化一定要加上read_only 而且在这里写了之后一定要到上面去注册
# publish_detail = serializers.SerializerMethodField(read_only=True)
# def get_publish_detail(self, obj):
# return {'name': obj.publish.name, 'addr': obj.publish.addr}
# author_list = serializers.SerializerMethodField(read_only=True)
#
# def get_author_list(self, obj):
# l1 = []
# for author in obj.authors.all():
# l1.append({'name': author.name, 'phone': author.phone})
# return l1
# 局部钩子和之前的是一样的
def validate_name(self, name):
if name.startswith('xxx'):
raise ValidationError('不能以xxx作为开头')
else:
return name
总结:
- 通过Meta和模型类强关联
- fields 是序列化的的所有字段
- extra_kwargs= 用来定制字段类的属性
- 如果是在fileds中写了__all__就是将模型表中的字段名全部复制了过来,做了个映射
- 还可以通过重写来定制字段类的属性
- 最后总结一句话,ModelSerializer继承了Serializer,所有的功能还是和之前一模一样,还能写一些自己的功能,更加的简洁,有了私有性。