zoukankan      html  css  js  c++  java
  • DRF十大请求

    1.二次封装Response

    # 新建一个response文件,让他继承Response,重新写他的__init__方法,
    from rest_framework.response import Response
    
    
    class APIResponse(Response):
    	# 重写方法
        def __init__(self, status=0, msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs ):
            data = {  # 状态码和数据状态信息
                'status': status,
                'msg': msg
            }
            if results is not None: # 判断是否有响应数据,有的话就添加
                data['results'] = results
                data.update(**kwargs) # 后台的一切自定义响应数据直接放到响应数据中去
    
            super().__init__( data=data, status=http_status, headers=headers, exception=exception)
            
    # 如何调用:
      # return Response({
                    #     'status': 1,
                    #     'msg': 'pk error'
                    # }, status=400)
        return APIResponse(1, 'pk error', http_status=400) # 传入对应的信息即可.
        
    
    

    2.设置基表

    # 设置了abstract为True的模型类,称之为基表,这样的模型类是专门作为基类来提供共有属性的.
    eg:
    class BaseModel(models.Model):
    	is_delete = model.BoolenField(default=False)
    	create_time = model.DateTimeField(auto_now_add=True) # 一般重复的字段
    	class Meta:
    		# 基表必须设置abstract,基表就是给普通Model类继承使用的,设置了abstract就不会完成数据库迁移完成建表,就是说这个模板表不会被创建.
    		abstract = True
    # 使用(可以多个表共同使用)
    class Book(BaseModel):  # 继承BaseModel,那么话就不用重写在写基类里面出现的字段.
    	name = models.CharField(max_length=32)
    	price = models.DecimalField(max_digits=5, decimal_places=2)
    

    3.ORM多表关联操作:

    外键所放位置:
    	一对多: 外键字段在多的一方
    	多对多: 外键在常用的一方
    	一对一: 外键在不常用的一方(如:作者可以没有详情,但是详情不能没有作者.)
    eg:
    	class Author(BaseModel):
    		name = models.CharField(max_length=32)
    		sex = models.IntegerField(choices=[(0,'男'),(1,'女')], default=0)
    		
    	class AtthoriDetail(BaseModel):
    		info = models.CharField(max_length=255)
    		author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)  # 放在不常用的作者详情表里
    		
    # 1.related_name='detail', 是规定反向查询字段,作者查详情是反向,可以通过这个字段来拿信息
    # 2.db_constraint=False, 让这个外键字段断开关联.
    
    关于外键间的级联关系on_delete字段的使用(在使用db_constraint断开关联之后使用.)
    	一对一: 作者没了,详情也就没了: on_delete=models.CASCADE
    	一对多: 出版社没了,书还是哪个出版社出版的: on_delete=models.DO_NOTHING
    	一对多: 部门没了,员工没有部门: null=True, on_delete=models.SET_NULL
    	一对多: 部门没了,员工进入默认部门(默认值): default=0, on_delete=models.SET_DEFAULT
    	多对多字段: 不能设置on_delete
    			
    

    4.联表序列化

    # 在Model类中定义插拔序列化方法属性,完成联表查询.
    
    class Book(BaseModel):
    	 name = models.CharField(max_length=16)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
        # 重点:多对多外键实际在关系表中,ORM默认关系表中两个外键都是级联
        # ManyToManyField字段不提供设置on_delete,如果想设置关系表级联,只能手动定义关系表
        authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
    
        # 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
        @property
        def publish_name(self):
            return self.publish.name
            
        @property
        def author_list(self):
            temp_author_list = []
            for author in self.authors.all():
                temp_author_list.append({
                    'name': author.name,
                    'sex': author.get_sex_display(),
                    'mobile': author.detail.mobile
                })
            return temp_author_list
            
    # 使用时: 在fields = ['publish_name', 'author_list']
    	
    

    5.子序列化

    # 如果只需要查有需求的接口,自定义深度就可以使用子序列化来完成.
    
    # 在自定义的serializers里:
    from rest_framework import serializers
    from . import models
    
    class BookModelSerializer(serializers.ModelSerializer):
    	class Meta:
    		
    		model = models.Book
    			fields = ['name', 'price', 'publish_name', 'author_list', 'publish', 'authors']
    			extra_kwargs = {
    				'publish': {
    					'write_only':True  # 只参与反序列化. 只写.
    				},
    				'authors': {
    					'write_only': True
    				}
    			}
    class PublishModelSerializer(serializer.ModelSerializer):
     	# 子序列化都是提供给外键(正向发向)完成深度查询的,外键字段是唯一:many:True,不为一:many:False
     	# 只能参与序列化, 且反序列化不能写(反序列外键字段会抛异常.)
    	books = BookModelSerializer(many=True) # 实现了子序列化
    	class Meta:
    		model = models.Publish
    		fields = ['name', 'address', 'books'] #这样查出版社就能查出书的信息.
    		
    	
    

    6.单查群查接口

    # 1.序列化类提供序列化对象,many参数控制着操作的数据是一条还是多条
    
    class BookAPIView(APIView):
    	# 单查,群查
    	def get(self, request, *args, **kwargs):
    		pk = kwargs.get('pk')  # 拿到pk值
    		if pk:  # 通过取到的pk值,拿到书籍对象,并查看数据有没有删除.		
    			book_obj = models.Book.objects.filter(pk=pk, is_delete_False).first
                if not book_obj:  # 没有拿到就抛错
                	return APIResponse(1, 'pk error', http_status=400)
                	# 如果正确就反回正确的数据(要序列化成前端能看的懂得数据)
                book_data = serializers.BookModelSerializer(book_obj).data
                return APIResponse(results=book_data)
            # 群查, 拿出所有并序列化返回.
            book_query = models.Book.object.filter(is_delete=False).all()
            return APIResponse(0, 'ok',data=serializers.BookModelSerializer(book_query, many=True).data)
    

    7.单删群删接口

    def delete(self, request, *args, **kwargs):
    	# 单删: 前台数据为pk, 接口为 /book/(pk)/
    	# 群删: 前台数据为pks, 接口为 /books/
    	
    	pk = kwargs.get('pk')
    	# 将单删和群删整合
    	if pk:
    		pks = [pk]
    	else:
    		pks = request.data.get('pks') # 群删拿到pks
    	if not pks:
    		return APIResponse(1, 'delete error', http_status=400)
    		# 判断有没有操作
    	rows = models.Book.object.filter(is_delete=False, pk__in=pks).update(is_delete=True)
    	if rows:
    		return APIResponse(0, 'delete ok')
    	return APIReponse(1, 'delete failed')
    

    8.单增群增接口

    def post(self, request, *args, **kwargs):
    	# 单增: 前台提供字典,
    	# 群增: 前台提供列表套字典,
    	request_data = request.data  # 拿到数据
    	if isinstance(request_data, dict):   # 单增(字典类型)isinstance封装好了
    		book_ser = serializer.BookModelSerializer(data=request_data) # 反序列化
    		if book_ser.is_valid():  # 判断数据通过就直接调用.save保存.
     			book_obj = book_ser.save()
     			retutn APIResponse(results=serializers.BookModelSerializer(book_obj).data)
     		return APIResponse(1, msg=book_ser.errors)
     		
     	elif isinstance(request_date, list) and len(request_data) != 0:
     		book_ser = serializers.BookModelSerializer(data=request_data, many=True)
     		book_ser.is_valid(raise_exception=True) # 它会自动反回错误信息.
     		book_obj_list = book_ser.save()
     		return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
     		
    

    9.单群整体改

    (和新增基本相同,只需要给instance赋值你要修改的对象)
    1.序列化类参数instance=修改的对象, data=修改的数据, partial=是否能过局部修改,单整体修改就是pritial=False(默认就是False)
    
    def patch(self, request, *args, **kwargs):
    	# 单整体改: 前台提交字典, 接口/books/(pk)/
    	# 群整体改: 前台提交列表套字典, 接口/books/ ,每一个字段都可以设置pk.
    	pk = kwargs.get('pk')
    	request_data = request.data
    	if pk:
    		try:
    			book_obj = models.Book.object.get(pk=pk)  #拿到单个
    		except: 
    			return APIResponse(1, 'pk error')  # 拿不到就抛错
    		 # 修改和新增,都需要通过数据,数据依旧给data,修改与新增不同点,instance要被赋值为被修改对象
                book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
                book_ser.is_valid(raise_exception=True)
                book_obj = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
                
         else:  # 群改
         	# 判断里面没有值, 抛错
         	if not isinstance(request_data, list) or len(request_data) == 0:
         		return APIResponse(1, 'data error', http_status=400)
         		#否则
         	obj_list = []
         	data_list = []
         	for dic in request_data:
         		try: 
         			pk = dic.pop('pk')  # 循环取到字典带的pk
         			try:
         				obj = models.Book.objects.get(pk=pk, is_delete=False)  # 循环取出对象
         				obj_list.append(obj)  # 存对象, 要修改的
         				data_list.append(dic)  # 字段数据,
         			except:
         				pass
         		except:
         			return APIResponse(1, 'data error', http_status=400)
         			# 之多了一个要修改的数据对象
         			book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True)
                book_ser.is_valid(raise_exception=True)
                book_obj_list = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
         	
    

    10.单群局部改

     # 单局部改、群局部改
        def patch(self, request, *args, **kwargs):
            """
            单整体改:前台提交字典,接口 /books/(pk)/
            群整体改:前台提交列表套字典,接口 /books/,注每一个字典都可以通过pk
            """
            pk = kwargs.get('pk')
            request_data = request.data
            if pk:
                try:
                    book_obj = models.Book.objects.get(pk=pk)
                except:
                    return APIResponse(1, 'pk error')
                # 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
                book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)
                book_ser.is_valid(raise_exception=True)
                book_obj = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
    
            else:  # 群改
                if not isinstance(request_data, list) or len(request_data) == 0:
                    return APIResponse(1, 'data error', http_status=400)
    
                # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
                # 要考虑pk对应的对象是否被删,以及pk没有对应的对象
                # 假设pk3被删,pk100没有 => [obj1] + [{...}]
    
                # 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作
                obj_list = []
                data_list = []
                for dic in request_data:
                    # request_data可能是list,单内部不一定是dict
                    try:
                        pk = dic.pop('pk')
                        try:
                            obj = models.Book.objects.get(pk=pk, is_delete=False)
                            obj_list.append(obj)
                            data_list.append(dic)
                        except:
                            pass
                    except:
                        return APIResponse(1, 'data error', http_status=400)
    
                book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True, partial=True)
                book_ser.is_valid(raise_exception=True)
                book_obj_list = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
    
    
    

    11.需要注意

    # 因为ModelSerializer没有提供群增群改,所以你需要关联ListSerializer来实现,但是ListSerializer又没有提供updata方法实现体, 如果你想用就需要重新写.
    
    class BookListSerializer(serializer.ListSerializer):
    
    	# 1.create 方法父级ListSerializer已经提供了
    	
    	# 2.父级ListSerializer没有通过update方法的实现体, 需要自己重写
    	return [
    		self.child.updata(instance[i], attrs) for i, attrs in enumerate(validated_data)
    	]
    	
    # class BookModelSerializer(serializers.ModelSerializer):
    	class Meta:
    		# 关联ListSerializer完成群增群改.
    		list_serializer_class = BookListSerializer
    
    
  • 相关阅读:
    Mysql JSON 新特性用法
    fastjson 使用技巧
    kafka 笔记
    nginx 使用教程
    spring boot 和 spring mvc 使用 jackson 包处理 忽略 null 字段返回
    jmeter 安装使用
    windows 下千万不要用 git的“换行符自动转换功能”
    ps grep awk 结合 xargs kill进程
    linux发行版版本及内核查看
    union 跟 order by同时使用
  • 原文地址:https://www.cnblogs.com/kangwy/p/11913420.html
Copyright © 2011-2022 走看看