serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法。ModelSerializer可以看成是Serializer的一个升级版,功能更强大,更方便。 实际上ModelSerializer类继承了Serializer类
序列化是把数据库里面的数据,转成json格式返回给用户,具体参考前面这篇https://www.cnblogs.com/yoyoketang/p/11538172.html 在models.py设计一个Goods商品表,里面包含多个字段和多个数据类型
from django.db import models
# Create your models here.
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class Goods(models.Model):
"""商品表"""
goods_name = models.CharField(max_length=30,
default="",
verbose_name="商品名称")
goods_code = models.CharField(max_length=30,
unique=True,
verbose_name="商品代号")
merchant_id = models.CharField(max_length=30,
default="",
blank=True, null=True,
verbose_name="商户ID")
merchant_name = models.CharField(max_length=30,
default="",
blank=True, null=True,
verbose_name="商户名称")
goods_price = models.FloatField(blank=True, null=True,
default=0,
verbose_name="商品价格")
goods_stock = models.IntegerField(blank=True, null=True,
default=0,
verbose_name="商品库存")
goods_groupid = models.IntegerField(blank=True, null=True,
default=0,
verbose_name="商品分组")
goods_status = models.IntegerField(choices=(
(0, '下架'),
(1, '出售中')
),
default=1,
verbose_name="0下架 1出售中")
price = models.FloatField(blank=True, null=True,
default=0,
verbose_name="成本价")
create_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
update_time = models.DateTimeField(auto_now=True, verbose_name="修改时间")
class Meta:
verbose_name_plural = '商品'
verbose_name = "商品信息"
def __str__(self):
return self.goods_code
视图继承 drf 的 APIView,这里写了2个方法,get 查询全部商品,序列化后返回json数据。 post 请求是创建商品。
from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser
from rest_framework.authentication import TokenAuthentication
from .models import Goods
# Create your views here.
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class GoodsSerializer(serializers.ModelSerializer):
"""序列化商品models"""
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
class Meta:
model = Goods
fields = '__all__' # 返回全部的字段
# exclude是不包含某些字段
# exclude = ["price"]
class GoodsAPIView(APIView):
"""商品视图"""
permission_classes = (AllowAny,) # AllowAny 允许所有用户
def get(self, request, *args, **kwargs):
"""返回所有的"""
goods = Goods.objects.all() # 查询全部
serializer = GoodsSerializer(instance=goods, many=True)
return Response({
"code": 0,
"msg": "success!",
"data": serializer.data
})
def post(self, request, *args, **kwargs):
"""提交数据"""
verify_data = GoodsSerializer(data=request.data)
if verify_data.is_valid():
save = verify_data.save()
return Response({
"code": 0,
"msg": "success!",
"data": GoodsSerializer(instance=save).data
})
else:
return Response({
"code": 10086,
"msg": "参数不合法",
"data": verify_data.errors
})
urls.py配置访问路由
from django.conf.urls import url
from yoyo import views
urlpatterns = [
url('^api/v1/goods/$', views.GoodsAPIView.as_view()),
]
什么是序列化呢?
当用户需要查询数据的时候,把数据库里面的数据转成我们需要的json数据,这个过程就是序列化
在get方法里实例化GoodsSerializer对象,传2个参数
def get(self, request, *args, **kwargs):
"""返回所有的"""
goods = Goods.objects.all() # 查询全部
serializer = GoodsSerializer(instance=goods, many=True)
上面这个过程就是序列化,序列化后输出数据serializer.data
什么是反序列化?
用户在添加商品的时候,需要把数据存到数据库,这个过程我们需要先校验是不是合法的。
对用户传入的数据,我们需要先清洗下,因为用户可能会传一些数据库表里面没有的字段,这些我们不需要,于是可以用到 GoodsSerializer(data=request.data)
data 用户传入的参数,通过request.data 获取,request.data 实际上跟之前request.POST 是一样的获取用户传过来的数据
is_valid() 校验数据是否合法
save() 保存之前,必须先调用is_valid(),保存后返回一个Goods object对象
上面这个过程,用户传过来的数据先清洗,校验数据合法性,再存入数据库的过程,就是反序列化
看过接口文档的应该知道,有些参数是必传的,有些是非必传的,那么我们可以在GoodsSerializer
控制字段的必传和非必传
详情参考前面这篇https://www.cnblogs.com/yoyoketang/p/14291206.html
class GoodsSerializer(serializers.ModelSerializer):
"""序列化商品models"""
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
# 必传字段
goods_code = serializers.CharField(required=True)
goods_stock = serializers.IntegerField(required=True)
class Meta:
model = Goods
fields = '__all__' # 返回全部的字段
序列化的时候,设置 goods_code 和 goods_stock 是必传字段,那么在添加商品的时候,如果不传就会提示
{"goods_code":["该字段是必填项。"],"goods_stock":["该字段是必填项。"]}}
如果在创建商品的时候,有些字段我不想让用户去修改,比如 goods_status(商品状态),默认就是出售中,
不想让用户创建的时候设置下架,于是可以忽略 goods_status(商品状态) 字段, 设置 read_only=True
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class GoodsSerializer(serializers.ModelSerializer):
"""序列化商品models"""
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
# 必传字段
goods_code = serializers.CharField(required=True)
goods_stock = serializers.IntegerField(required=True)
# 忽略字段,设置read_only=True
goods_status = serializers.IntegerField(read_only=True)
class Meta:
model = Goods
fields = '__all__' # 返回全部的字段
现在不管 goods_status 传什么都不会影响保存结果
校验 goods_code 字符串长度是8-15位,校验goods_stock 整数范围是1-10000
class GoodsSerializer(serializers.ModelSerializer):
"""序列化商品models"""
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
# 必传字段
goods_code = serializers.CharField(required=True,
max_length=15,
min_length=8)
goods_stock = serializers.IntegerField(required=True,
min_value=1,
max_value=10000)
# 忽略字段,设置read_only=True
goods_status = serializers.IntegerField(read_only=True)
class Meta:
model = Goods
fields = '__all__' # 返回全部的字段
这时候就会对传入的字符串和整数范围做校验
如果我想用户的商品code命名,必须按sp开头,针对某个字段单独写校验方式,可以自定义 validate_<field_name>
verify_data.errors
显示# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class GoodsSerializer(serializers.ModelSerializer):
"""序列化商品models"""
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
# 必传字段
goods_code = serializers.CharField(required=True,
max_length=15,
min_length=8)
goods_stock = serializers.IntegerField(required=True,
min_value=1,
max_value=10000)
# 忽略字段,设置read_only=True
goods_status = serializers.IntegerField(read_only=True)
def validate_goods_code(self, value):
"""校验字段 validate_<Field>"""
if not value.startswith("sp"):
raise serializers.ValidationError("goods_code 不是 sp 开头")
return value
class Meta:
model = Goods
fields = '__all__' # 返回全部的字段
如果我想校验 goods_price(商品售卖价格)不能小于 (price)成本价, 万一哪个运营设置商品价低于成本价,那不得亏惨! 这里涉及到传入参数的2个值互相校验
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class GoodsSerializer(serializers.ModelSerializer):
"""序列化商品models"""
create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
# 必传字段
goods_code = serializers.CharField(required=True,
max_length=15,
min_length=8)
goods_stock = serializers.IntegerField(required=True,
min_value=1,
max_value=10000)
# 忽略字段,设置read_only=True
goods_status = serializers.IntegerField(read_only=True)
def validate_goods_code(self, value):
"""校验字段 validate_<Field>"""
if not value.startswith("sp"):
raise serializers.ValidationError("goods_code 不是 sp 开头")
return value
def validate(self, attrs):
"""自定义校验"""
goods_price = attrs.get('goods_price', 0)
price = attrs.get('price', 0)
if goods_price < price:
raise serializers.ValidationError('goods_price 不能小于 price')
return attrs
class Meta:
model = Goods
fields = '__all__' # 返回全部的字段