关键词:
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
drf学习(代码片段)
...口-单查、群查、单增、单局部改、单整体改、单删一共十大接口:群增、群局部改、群整体改、群删'''接口'''接口概念:前后台进行数据交互的媒介--url链接接口组成:url链接-唱得像返回数据的url链接请求方... 查看详情
drf框架知识总览(代码片段)
...口-单查、群查、单增、单局部改、单整体改、单删一共十大接口-群增、群局部改、群整体改、群删"""接口"""接口概念:前台与后台进行信息交互的媒介-url链接接口组成:url链接-长得像返回数据的url链接... 查看详情
drf请求与响应(代码片段)
1请求和响应1.1RequestRESTframework传入视图的request对象不再是Django默认的HttpRequest对象,而是RESTframework提供的扩展了HttpRequest类的Request类的对象。RESTframework提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类... 查看详情
drf之请求与相应(代码片段)
一、请求对象 1、重新封装了原request。 2、request._request:原request对象。 3、request.data:前端post过来的三种编码格式的数据,都可以从中取出。 4、request.query_params:url携带的参数,相当于原来的request.GET。 5、re... 查看详情
drf序列化器之请求响应以及视图(代码片段)
1.http请求处理drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作。所以在django原有的django.views.View类基础上,drf封装了多个视图子类出来提供给我们使用。DjangoRESTframwork提供的视图的主要作用:控制序列化器的... 查看详情
drf请求与响应(代码片段)
目录一请求与响应1.1Request1.1.1.1常用属性1).data2).query_params1.2Response1.1.2.1构造方式1.1.2.2常用属性1).data2).status_code3).content1.1.2.3状态码1)信息告知-1xx2)成功-2xx3)重定向-3xx4)客户端错误-4xx5)服务器错误-5xx二视图2.2视图2.2.... 查看详情
drf视图类关系详解(代码片段)
概要:#1请求和响应#2请求Request对象,drf新包装的,Request.data,Request.query_params,重写了__getattr__,request._request#3json模块是否执行反序列化bytes格式#4考你:视图类的方法中:self.request,就是当次请求的request#5Response:类,实例化传一... 查看详情
drf-解析器组件(代码片段)
...引入DjangoRestFramework帮助我们实现了处理application/json协议请求的数据,另外,我们也提到,如果不使用DRF,直接从request.body里面拿到原始的客户端请求的字节数据,经过decode,然后json反序列化之后,也可以得到一个Python字典类型... 查看详情
drf教程7-认证(代码片段)
Authentication 认证是将一个传入的请求和一组标识凭据相关联的机制,比如请求过来的用户,或者用户登录时携带的token。 然后权限策略就能使用这些凭据来决定是否允许这个请求。 REST框架提供了多种开箱即用的方案... 查看详情
drf初识(代码片段)
...ostman的安装YAPI的使用drf:Django-restframework接口规定了提交请求参数的请求方式,访问其可以获取响应的反馈数据的url链接;url链接:请求方法+请求参数+响应数据结果;drf框架安装#使用drf时,要在settings中注册pipinstalldjangorestframe... 查看详情
drf获取请求过来时的request(代码片段)
0.获取请求过来时的request"""获取请求时带过来的request,结合drf认证组件,判断用户的登录状态,来获取用户的粒度操作,比如点赞/收藏/关注的取消与私有化,示例:用在序列化中的字段钩子方法"""fromrest_... 查看详情
drf之路由系统与视图(代码片段)
手动路由编写#路由fromdjango.conf.urlsimporturlfromapp01.viewsimportUserListViewurlpatterns=[#GET请求查询所有#POST请求增加url(r'^users/$',UserListView.as_view()),url(r'^users.(?P<format>w+)/$',Us 查看详情
drf缓存(代码片段)
...于现在的动态网站来讲,所有的界面展示都是通过客户端请求服务端,服务端再去请求数据库,然后将请求到的数据渲染后返回给客户端。用户每次访问页面都需要去请求数据库,如果同时有多个人访问的话,对于我们的数据库... 查看详情
drf模块及源码(代码片段)
drf中的APIView请求生命周期APIView的as_view(局部禁用csrf)=>调用父类view中的as_view返回view()方法=>自己的类调用自己的dispatch方法发送请求(drf的displatch中重写了错误分支,可以判断三大认证之前的错误,保证服务端请求安全,也可以判... 查看详情
drf之解析器组件及序列化组件(代码片段)
...我们已经有了一个共识,Django无法处理application/json协议请求的数据,即,如果用户通过application/json协议发送请求数据到达Django服务器,我们通过request.POST获取到的是一个空对象。 DjangoRestFramework帮助我们实现了处理application/... 查看详情
drf08(代码片段)
...继承APIView类,也只有APIView类中才有dispatch方法,所以所有的请求都要经过三大认证,认证通过后执行相应请求的视图函数defdispatch(self,request,*args,**kwargs):"..."try:#三大认证self.initial(request,*args,**kwargs)"..."exceptExceptionasexc:#... 查看详情
drf模块分析(代码片段)
drf请求模块、渲染模板、解析模块、响应模块、异常模块请求模块drf的请求模块1、drf的request是在wsgi的request基础上再次封装2、wsgi的request作为drf的request一个属性:_request3、新的request对旧的request做了完全兼容4、新的request对数据... 查看详情
django(63)drf权限源码分析与自定义权限(代码片段)
前言上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析源码入口:APIView.py文件下的initial方法下的check_permissionsdefcheck_permissions(self,request):"""检查是否应... 查看详情