「Django」rest_framework学习系列-序列化
序列化
方式一 :在业务类里序列化数据库数据
class RolesView(APIView): def get(self,request,*args,**kwargs): roles = models.Role.objects.all().values('id','title')[1:3] ret = list(roles) r = json.dumps(ret,ensure_ascii=False) return HttpResponse(r)
方式二:写个序列化的类,在业务类中引用,序列化类中可以定制字段
class UserinfoSerializer(serializers.ModelSerializer): #字段名与数据库相同则替换,不同则添加 type = serializers.CharField(source='get_usertype_display') gb = serializers.CharField(source='group.title') class Meta: model = models.UserInfo #全部显示 fields = '__all__' #定制显示 # fields = ['id','username','type','gb']
class UserInfo(models.Model): usertype_choices = ( (1,'普通用户'), (2,'VIP用户'), (3,'SVIP用户') ) usertype = models.IntegerField(choices=usertype_choices,verbose_name='用户类型') username = models.CharField(max_length=32,unique=True,verbose_name='用户名') password = models.CharField(max_length=64,verbose_name='密码') group = models.ForeignKey('UserGroup',on_delete=models.DO_NOTHING,verbose_name='分组') roles = models.ManyToManyField('Role',verbose_name='职业') class Meta: verbose_name = '用户管理' verbose_name_plural = verbose_name def __str__(self): return self.username
class UserInfoView(APIView): authentication_classes = [] permission_classes = [] def get(self,request,*args,**kwargs): m = models.UserInfo.objects.all() ser = UserinfoSerializer(instance=m,many=True) #单表的话这里many = false return Response(ser.data)
方式二补充:source不适合many to many,many to many需要自定义显示
role = serializers.SerializerMethodField() #自定义显示 def get_role(self,row): role_list = row.roles.all() ret = [] for item in role_list: ret.append({'id':item.id,'title':item.title}) return ret
方式三:depth根本连表结构往深层取值
class UserinfoSerializer(serializers.ModelSerializer): usertype = serializers.CharField(source='get_usertype_display') class Meta: model = models.UserInfo #全部显示 fields = '__all__' depth = 1 #0~10之间 #定制显示 # fields = ['id','username','type','gb']
[{"id": 1, "usertype": 1, "username": "wrx", "password": "123", "group": {"id": 1, "title": "A组"}, "roles": [{"id": 2, "title": "老师"}, {"id": 3, "title": "医生"}]}, {"id": 2, "usertype": 2, "username": "ylp", "password": "123", "group": {"id": 2, "title": "B组"}, "roles": [{"id": 3, "title": "医生"}]}]
方式四:生成链接,即把上述类的group生成链接
class UserinfoSerializer(serializers.ModelSerializer): usertype = serializers.CharField(source='get_usertype_display') group = serializers.HyperlinkedIdentityField(view_name='grp',lookup_field='group_id',lookup_url_kwarg='pk') #name,pk值对应urls中的re-path class Meta: model = models.UserInfo #全部显示 fields = '__all__' depth = 1 #0~10之间 #定制显示 # fields = ['id','username','type','gb']
re_path(r'^(?P<version>[v1|v2]+)/group/(?P<pk>\d+)$',GroupView.as_view(),name='grp')
PS:这里经历了一个错误,如果配置了全局的版本控制(详见版本控制配置),这里要也要配置,否则会一直报错
django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "grp". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
class UserInfoView(APIView): def get(self,request,*args,**kwargs): m = models.UserInfo.objects.all() ser = UserinfoSerializer(instance=m,many=True,context={'request':request}) return Response(ser.data)
PS:实例这个定制类的时候要加要加context={'request':request}
实际调用的是另一个views类的url
class GroupSerializer(serializers.ModelSerializer): class Meta: model = models.UserGroup fields = '__all__' class GroupView(APIView): def get(self,request,*args,**kwargs): pk = kwargs.get('pk') obj = models.UserGroup.objects.filter(pk=pk).first() ser = GroupSerializer(instance=obj, many=False) t = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(t)
方式五:三张表互相关联的反向查找
class Course(models.Model): title = models.CharField(max_length=32,verbose_name='课程名称') course_img = models.ImageField(verbose_name='课程图片',upload_to = "static/img/") course_choice = ( (0, '入门级'), (1, '普通难度'), (2, '中等难度'), (3, '高级难度'), ) level = models.IntegerField(verbose_name='课程难度',choices=course_choice,default=0) class Meta: verbose_name = '课程管理' verbose_name_plural = verbose_name def __str__(self): return self.title class CourseInfo(models.Model): why = models.CharField(verbose_name='课程描述',max_length=255) course = models.OneToOneField(to='Course',on_delete=models.DO_NOTHING,verbose_name='关联课程') recommend_course = models.ManyToManyField(to='Course',verbose_name='推荐课程',related_name='rc') class Meta: verbose_name = '课程详细' verbose_name_plural = verbose_name def __str__(self): return '课程详细:'+self.course.title class Section(models.Model): num = models.IntegerField(verbose_name='章节') name = models.CharField(max_length=64,verbose_name='课程章节') course = models.ForeignKey(to='Course', on_delete=models.DO_NOTHING, verbose_name='关联课程') class Meta: verbose_name = '课程章节' verbose_name_plural = verbose_name def __str__(self): return '课程章节'+self.course.title
PS:第二张表与第一张表多对多并且单对单(这里有个小知识点,同时多对多和单对单的时候有一张表要加related_name='rc'),第三张表与第一张表一对多,需求:通过序列化第二张表得到第一张表和第三张表的相关内容
class CourseinfoSerializer(serializers.ModelSerializer): #单对单,单对多,choice可以用这种方式,多对多不能使用 title = serializers.CharField(source='course.title') level = serializers.CharField(source='course.get_level_display') #多对多需要自定义 recommends = serializers.SerializerMethodField() def get_recommends(self, row): role_list = row.recommend_course.all() ret = [] for item in role_list: ret.append({'id': item.id, 'title': item.title}) return ret #3张表互相关联的反向查找 sections = serializers.SerializerMethodField() def get_sections(self, row): role_list = row.course.section_set.all() ret = [] for item in role_list: ret.append({'num': item.num, 'name': item.name}) return ret class Meta: model = models.CourseInfo # fields = '__all__' fields = ['id','title','level','why','recommends','sections'] # depth = 2
def retrieve(self,request, *args, **kwargs): ret = {'code': 1000, 'data': None} pk = kwargs.get('pk') try: obj = models.CourseInfo.objects.filter(course_id=pk) ser = sl.CourseinfoSerializer(instance=obj, many=True) ret['data'] = ser.data except Exception as e: ret['code'] = 1001 ret['error'] = '获取课程失败' return Response(ret)
PS:这实际是个类的get请求,re_path(r'^course/(?P<pk>\d+)$',views.CourseView.as_view({'get':'retrieve'})),
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
序列化-数据验证,验证title数据不能为空且必须以wrx开头
class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required':'标题不能为空'},) def validate_title(self,value): if not value.startswith('wrx'): message = '标题必须以%s开头'%'wrx' raise exceptions.ValidationError(message) else: return value
class UserGroupView(APIView): def post(self,request,*args,**kwargs): src = '' res = UserGroupSerializer(data=request.data) if res.is_valid(): print(res.validated_data) src = str(res.validated_data['title']) else: print(res.errors) src = str(res.errors) return HttpResponse(src)