天天看点

DRF学习笔记(1)

目录​

​​restful规范: 2​​​

​​django rest framework 3​​​

​​serializers.Serializer 5​​​

​​serializers.ModelSerializer: 7​​​

​​api FBV: 8​​​

​​drf的request和response 10​​​

​​rest_framework.decorators.api_view和rest_framework.views.APIView: 13​​​

​​api CBV,rest_framework.views.APIView: 14​​​

​​api CBV,使用rest_framework.mixins: 15​​​

​​api CBV,ListAPIView|CreateAPIView|RetrieveAPIView|DestroyAPIView|UpdateAPIView|ListCreateAPIView 16​​​

​​rest_framework.viewsets和rest_framework.routers.DefaultRouter: 18​​​

​​分页: 20​​​

​​认证: 21​​​

​​授权: 26​​​

​​面试题目: 27​​​

​​django请求生命周期 27​​​

​​csrf 29​​​

​​权限 32​​​

​​节流 33​​​

​​版本 35​​​

​​解析器: 37​​​

​​序列化 38​​​

​​序列化-序列化: 39​​​

​​序列化-请求数据校验: 45​​​

​​渲染 47​​​

​​分页 49​​​

​​视图 52​​​

​​路由 55​​​

​​content-type 57​​​

​​drf的api文档自动生成: 60​​​

​​drf对象级别的权限支持: 61​​​

​​drf的过滤: 61​​​

​​使用方式1: 62​​​

​​使用方式2: 63​​​

​​例,多IP查询: 63​​​

​​drf的搜索和排序 63​​​

​​例,排序(django_filters.OrderingFilter): 67​​​

​​例,排序(rest_framework.filters.OrderingFilter): 68​​​

​​例,高级搜索: 68​​​

​​drf的token 69​​​

​​jwt方式,用户认证 70​​​

​​drf的缓存: 71​​​

​​social_django实现第三方登录 72​​​

​​Tokne的设计及加密方法 73​​​

系统之间为了调用数据,用api;​

格式:​

json;​

xml;​

给用户提供一个接口前:​

1.跟前端进行交互,确定前端要什么;​

2.把需求写个文档;​

restful规范:​

restful api是用于前端和后台进行通信的一套规范,使用这个规范可以让前后端开发变得更加轻松;​

数据传输格式,都用json,而不是xml;​

url链接,只能有名词,不能有动词,名词的复数要加s;​

restful是一种软件架构风格或者说是一种设计风格,并不是标准,它只是提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。​

就像设计模式一样,并不是一定要遵循这些原则,而是基于这个风格设计的软件可以更简洁,更有层次,我们可以根据开发的实际情况,做相应的改变。​

如一些规范:​

1、restful提倡面向资源编程,在url接口中尽量要使用名词,不要使用动词;​

2、在url接口中推荐使用https协议,让网络接口更加安全,Https是Http的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL(安全套接层协议);​

​​https://www.bootcss.com/v1/mycss?page=3; ​​​

3、在url中可以体现版本号,https://v1.bootcss.com/mycss,不同的版本可以有不同的接口,使其更加简洁,清晰; ​

4、url中可以体现是否是API接口,https://www.bootcss.com/api/mycss;​

5、url中可以添加条件去筛选匹配,https://www.bootcss.com/v1/mycss?page=3;​

6、可以根据Http不同的method,进行不同的资源操作,5种方法:GET|POST|PUT|DELETE|PATCH;​

7、响应式应该设置状态码;​

8、有返回值,而且格式为统一的json格式; ​

9、返回错误信息,返回值携带错误信息;​

10、返回结果中要提供帮助链接,即API最好做到Hypermedia,如果遇到需要跳转的情况携带调转接口的URL;​

ret = {​

code: 1000,​

data:{​

id:1,​

小强',​

depart_id:http://www.luffycity.com/api/v1/depart/8/​

}​

}​

状态码 原生描述 描述​

200 OK 服务器成功响应客户端的请求​

400 INVALID REQUEST 用户发出的请求有错误,服务器没有进行新建或修改数据的操作​

401 Unauthorized 用户没有权限访问这个请求​

403 Forbidden 因为某些原因禁止访问这个请求​

404 NOT FOUND 用户发送的请求的url不存在​

405 Method not allowed 方法不被允许​

406 NOT Accept 用户请求不被服务器接收(比如服务器期望客户端发送某个字段,但没有发送)​

500 Internal server error 服务器内部错误,比如出现了bug​

204 No Content​

服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息,响应可能通过实体头部的形式,返回新的或更新后的元信息,如果存在这些头部信息,则应当与所请求的变量相呼应;​

如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档;​

由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾;​

django rest framework​

是django用来restful api的框架,风格完全和django一样,使用起来像是django本身提供的;​

​​https://www.django-rest-framework.org/​​​

(webproject) C:\webproject\mysite>pip install djangorestframework另coreapi,drf的文档支持;django-guardian,drf对象级别的权限支持​

INSTALLED_APPS = [​

'rest_framework',​

用djangorestframework:​

能自动生成符合 RESTful 规范的 API​

1.在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本一样,这部分的代码可以简写;​

2.在序列化与反序列化时,虽然操作的数据不同,但是执行的过程却相似,这部分的代码也可以简写;​

REST framework可以帮助简化上述两部分的代码编写,大大提高REST API的开发速度​

组件:​

1.序列化组件:serializers,对queryset序列化|对请求数据反序列化并格式校验;​

2.路由组件routers ,进行路由分发;​

3.视图组件ModelViewSet,帮助开发者提供了一些类,并在类中提供了多个方法;​

4.认证组件,写一个类并注册到认证类(authentication_classes),在类的的authticate方法中编写认证逻辑;​

5.权限组件,写一个类并注册到权限类(permission_classes),在类的的has_permission方法中编写认证逻辑,​

6.频率限制,写一个类并注册到频率类(throttle_classes),在类的的allow_request|wait方法中编写认证逻辑;​

7.解析器,选择对数据解析的类,在解析器类中注册(parser_classes);​

8.渲染器,定义数据如何渲染到到页面上,在渲染器类中注册(renderer_classes);​

9.分页,对获取到的数据进行分页处理,pagination_class;​

10.版本,版本控制用来在不同的客户端使用不同的行为,在url中设置version参数,用户请求时候传入参数,在request.version中获取版本,根据版本不同做不同处理;​

django rest framework框架中的视图都可以继承哪些类?​

class View(object):​

class APIView(View): #封装了view,并且重新封装了request,初始化了各种组件​

class GenericAPIView(views.APIView):增加了一些属性和方法,如get_queryset,get_serializer​

class GenericViewSet(ViewSetMixin, generics.GenericAPIView)父类ViewSetMixin 重写了as_view,返回return csrf_exempt(view),并重新设置请求方式与执行函数的关系​

class ModelViewSet(mixins.CreateModelMixin,​

mixins.RetrieveModelMixin,​

mixins.UpdateModelMixin,​

mixins.DestroyModelMixin,​

mixins.ListModelMixin,​

GenericViewSet):pass继承了mixins下的一些类,封装了list,create,update等方法和GenericViewSet​

简述 django rest framework框架的认证流程​

1.用户请求走进来后,走APIView,初始化了默认的认证方法​

2.走到APIView的dispatch方法,initial方法调用了request.user​

3.如果我们配置了认证类,走我们自己认证类中的authentication方法​

django rest framework如何实现的用户访问频率控制​

使用IP|用户账号,作为键,每次的访问时间戳作为值,构造一个字典形式的数据,存起来,每次访问时对时间戳列表的元素进行判断,把超时的删掉,再计算列表剩余的元素数就能做到频率限制了 ​

匿名用户,使用IP控制,但是无法完全控制,因为用户可以换代理IP登录用户;使用账号控制,但是如果有很多账号,也无法限制;​

rest_framework序列化组件的作用,以及一些外键关系的钩子方法​

作用:帮助我们序列化数据​

1.choices get_字段名_display​

2.ForeignKey source=orm 操作​

3.ManyToManyFiled SerializerMethodField()​

字段名():​

自定义​

serializers.Serializer​

from rest_framework import serializers​

class Serializer(BaseSerializer):​

class ModelSerializer(Serializer):​

class HyperlinkedModelSerializer(ModelSerializer):​

rest_framework.serializers.Serializer和django.forms.Form:​

功能一样,都是将用户提交的数据转为py数据结构,可用此来完成校验;​

Form用在post提交中的form表单;​

Serializer用在用户提交的json;​

另,​

from django.core import serializers的serializer虽可简单实现序列化,但有2个缺点,1字段序列化定死的,要想重组很麻烦,2images保存的是一个相对路径还需要补全,drf可自动补全​

def serialize(format, queryset, **options): #serializers.serialize​

例:​

from rest_framework import serializers​

from .models import Author​

class AuthorSerializer(serializers.Serializer): ​

id = serializers.IntegerField(read_only=True)​

first_name = serializers.CharField(max_length=100)​

last_name = serializers.CharField(required=False, allow_blank=True, max_length=100)​

email = serializers.EmailField(required=False, allow_blank=True, max_length=100)​

def create(self, validated_data):​

return Author.objects.create(**validated_data)​

def update(self, instance, validated_data):​

instance.first_name = validated_data.get('first_name', instance.first_name)​

instance.last_name = validated_data.get('last_name', instance.last_name)​

instance.email = validated_data.get('email', instance.email)​

instance.save()​

return instance​

底层实现:​

>>> from books.serializer import AuthorSerializer​

>>> from rest_framework.renderers import JSONRenderer #py结构-->json​

>>> from rest_framework.parsers import JSONParser #json-->py结构​

>>> from books.models import Author​

>>> Author.objects.all()​

<QuerySet [<Author: chai jowin>, <Author: dsfdfd sfdsfdsf>]>​

>>> a = Author.objects.get(id=1)​

>>> s = AuthorSerializer(a)​

>>> s.data #dict​

{'last_name': 'jowin', 'email': '[email protected]', 'id': 1, 'first_name': 'chai'}​

>>> content = JSONRenderer().render(s.data)​

>>> content​

b'{"id":1,"first_name":"chai","last_name":"jowin","email":"[email protected]"}'​

>>> from django.utils.six import BytesIO​

>>> stream = BytesIO(content)​

>>> stream​

<_io.BytesIO object at 0x00000000046389E8>​

>>> data = JSONParser().parse(stream)​

>>> data​

{'last_name': 'jowin', 'email': '[email protected]', 'id': 1, 'first_name': 'chai'}​

>>> s = AuthorSerializer(data=data)​

>>> s​

AuthorSerializer(data={'last_name': 'jowin', 'email': '[email protected]', 'id': 1, 'first_name': 'chai'}):​

id = IntegerField(read_only=True)​

first_name = CharField(max_length=100)​

last_name = CharField(allow_blank=True, max_length=100, required=False)​

email = EmailField(allow_blank=True, max_length=100, required=False)​

>>> s.is_valid()​

True​

>>> s.validated_data返回ordereddict​

OrderedDict([('first_name', 'chai'), ('last_name', 'jowin'), ('email', '[email protected]')])​

>>> s.save()​

<Author: chai jowin>​

>>> Author.objects.all()​

<QuerySet [<Author: chai jowin>, <Author: dsfdfd sfdsfdsf>, <Author: chai jowin>]>​

>>> s = AuthorSerializer(Author.objects.all(), many=True)序列化多个对象时要加many=True,调用many_init()​

>>> s.data​

[OrderedDict([('id', 1), ('first_name', 'chai'), ('last_name', 'jowin'), ('email', '[email protected]')]), OrderedDict([('id', 2), ('first_name', 'dsfdfd'), ('la​

st_name', 'sfdsfdsf'), ('email', '[email protected]')]), OrderedDict([('id', 3), ('first_name', 'chai'), ('last_name', 'jowin'), ('email', '[email protected]')])​

]​

serializers.ModelSerializer:​

rest_framework.serializers.ModelSerializer同django.forms.ModelForm;​

class ModelSerializer(Serializer):​

serializer_field_mapping = {​

models.AutoField: IntegerField,​

models.BigIntegerField: IntegerField,​

models.BooleanField: BooleanField,​

models.CharField: CharField,​

models.CommaSeparatedIntegerField: CharField,​

models.DateField: DateField,​

models.DateTimeField: DateTimeField,​

models.DecimalField: DecimalField,​

models.EmailField: EmailField,​

models.Field: ModelField,​

models.FileField: FileField,​

models.FloatField: FloatField,​

models.ImageField: ImageField,​

models.IntegerField: IntegerField,​

models.NullBooleanField: NullBooleanField,​

models.PositiveIntegerField: IntegerField,​

models.PositiveSmallIntegerField: IntegerField,​

models.SlugField: SlugField,​

models.SmallIntegerField: IntegerField,​

models.TextField: CharField,​

models.TimeField: TimeField,​

models.URLField: URLField,​

models.GenericIPAddressField: IPAddressField,​

models.FilePathField: FilePathField,​

}​

例:​

class Serializer(serializers.ModelSerializer):​

project_cname = serializers.ReadOnlyField(source='project_name.project_cname')​

pool_cname = serializers.ReadOnlyField(source='pool_name.pool_cname')​

project_name = serializers.IntegerField(source='project_name_id')​

owner_name = serializers.ReadOnlyField(source='owner.user')​

update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', required=False)​

class Meta:​

model = AppConfig​

fields = '__all__'​

例:​

class AuthorSerializer(serializers.ModelSerializer):​

class Meta:​

model = Author​

fields = ['id', 'first_name', 'last_name', 'email']​

api FBV:​

例:​

from django.http import HttpResponse​

from rest_framework.renderers import JSONRenderer​

from rest_framework.parsers import JSONParser​

from .serializer import AuthorSerializer​

from .models import Author​

from django.views.decorators.csrf import csrf_exempt​

class JSONResponse(HttpResponse):可用django.http.JsonResponse​

def __init__(self, data, **kwargs):​

content = JSONRenderer().render(data)​

kwargs['content_type'] = 'application/json'​

super(JSONResponse, self).__init__(content, **kwargs)同super().__init__(content, **kwargs)​

@csrf_exempt​

def author_list(request):​

if request.method == 'GET':​

authors = Author.objects.all()​

serializer = AuthorSerializer(authors, many=True)​

return JsonResponse(serializer.data, safe=False) # 默认safe=True,In order to allow non-dict objects to be serialized set the safe parameter to False.​

elif request.method == 'POST':​

data = JSONParser().parse(request)​

serializer = AuthorSerializer(data=data)​

if serializer.is_valid():​

serializer.save()​

return JSONResponse(serializer.data, status=201)​

return JSONResponse(serializer.errors, status=400)​

@csrf_exempt​

def author_detail(request, pk):​

try:​

author = Author.objects.get(pk=pk)​

except Author.DoesNotExist:​

return JSONResponse(status=404)​

if request.method == 'GET':​

serializer = AuthorSerializer(author)​

return JSONResponse(serializer.data)​

elif request.method == 'PUT':​

data = JSONParser().parse(request)​

serializer = AuthorSerializer(author, data=data)​

if serializer.is_valid():​

serializer.save()​

return JSONResponse(serializer.data)​

return JSONResponse(serializer.errors, status=400)​

elif request.method == 'DELETE':​

author.delete()​

return JSONResponse('', status=204)​

url(r'^authors/$', api.author_list, name='author_list'),​

url(r'^authors/(?P<pk>[0-9]+)/$', api.author_detail, name='author_detail'),​

drf的request和response​

REST framework的Request类扩展与标准的HttpRequest,并做了相应的增强,比如更加灵活的请求解析(request parsing)和认证(request authentication);​

Request解析​

REST framwork的Request对象提供了灵活的请求解析,允许你使用JSON data或其他media types像通常处理表单数据一样处理请求;​

.data #request.data 返回请求主题的解析内容,这跟标准的request.POST.get('username')和request.FILES类似,并且还具有以下特点:包括所有解析的内容,文件(file)和非文件(non-file inputs);支持解析POST以外的HTTP method,比如 PUT|PATCH;更加灵活,不仅仅支持表单数据,传入同样的JSON数据一样可以正确解析,并且不用做额外的处理(意思是前端不管提交的是表单数据,还是JSON数据,.data 都能够正确解析)​

.query_params #request.query_params等同于 request.GET,不过其名字更加容易理解,为了代码更加清晰可读,推荐使用 request.query_params,而不是Django中的request.GET,任何HTTP method类型都可能包含查询参数(query parameters),而不仅仅只是GET请求​

.parser #APIView类或者@api_view装饰器将根据视图上设置的parser_classes或settings文件中的 DEFAULT_PARSER_CLASSES设置来确保此属性.parsers自动设置为Parser实例列表,通常不需要关注该属性,如果你非要看看它里面是什么,可以打印出来看看,大概长这样:​

[<rest_framework.parsers.JSONParser object at 0x7fa850202d68>, <rest_framework.parsers.FormParser object at 0x7fa850202be0>, <rest_framework.parsers.MultiPartParser object at 0x7fa850202860>]​

包含三个解析器JSONParser,FormParser,MultiPartParser​

注意:​

如果客户端发送格式错误的内容,则访问request.data可能会引发ParseError,默认情况下,REST framework的APIView类或者 @api_view装饰器将捕获错误并返回400 Bad Request响应,如果客户端发送的请求内容无法解析(不同于格式错误),则会引发UnsupportedMediaType异常,默认情况下会被捕获并返回415 Unsupported Media Type 响应​

Responses​

与基本的HttpResponse对象不同,TemplateResponse对象保留了视图提供的用于计算响应的上下文的详细信息,直到需要时才会计算最终的响应输出,也就是在后面的响应过程中进行计算;​

REST framework 通过提供一个Response类来支持HTTP内容协商,该类允许你根据客户端请求返回不同的表现形式(如:JSON,HTML等)​

Response类的子类是Django的SimpleTemplateResponse,Response对象使用数据进行初始化,数据应由Python对象(native Python primitives)组成,然后REST framework使用标准的HTTP内容协商来确定它应该如何渲染最终响应的内容;​

当然,您也可以不使用Response类,直接返回常规HttpResponse或StreamingHttpResponse对象,使用Response类只是提供了一个更好的交互方式,它可以返回多种格式;​

除非由于某种原因需要大幅度定制REST framework,否则应该始终对返回Response对象的视图使用APIView类或@api_view装饰器,这样做可以确保视图执行内容协商,并在视图返回之前为响应选择适当的渲染器;​

创建response​

Response() #与普通HttpResponse对象不同,您不会使用渲染的内容实例化Response对象,相反您传递的是未渲染的数据,可能包含任何Python对象,由于Response类使用的渲染器不能处理复杂的数据类型(比如 Django 的模型实例),所以需要在创建Response对象之前将数据序列化为基本的数据类型;你可以使用REST framework的Serializer类来执行序列化的操作,也可以用自己的方式来序列化,构造方法: Response(data, status=None, template_name=None, headers=None, content_type=None)​

参数:​

data #响应的序列化数据​

status #响应的状态代码默认为200​

template_name #选择HTMLRenderer时使用的模板名称​

headers #设置HTTP header,字典类型​

content_type #响应的内容类型,通常渲染器会根据内容协商的结果自动设置,但有些时候需要手动指定​

属性​

.data #还没有渲染,但已经序列化的响应数据​

.status_code #状态码​

.content #将会返回的响应内容,必须先调用.render()方法,才能访问.content​

.template_name #只有在response的渲染器是HTMLRenderer或其他自定义模板渲染器时才需要提供​

.accepted_renderer #用于将会返回的响应内容的渲染器实例,从视图返回响应之前由APIView或@api_view自动设置​

.accepted_media_type #内容协商阶段选择的媒体类型,从视图返回响应之前由APIView或@api_view自动设置​

.renderer_context #将传递给渲染器的.render()方法的附加的上下文信息字典,从视图返回响应之前由APIView或@api_view自动设置​

标准HttpResponse属性​

Response类扩展于SimpleTemplateResponse,并且响应中也提供了所有常用的属性和方法,如您可以用标准方式在响应中设置header:​

response = Response()​

response['Cache-Control'] = 'no-cache'​

.render() #与其他任何TemplateResponse一样,调用此方法将响应的序列化数据呈现为最终响应内容,响应内容将设置为在accepted_renderer实例上调用.render(data,accepted_media_type,renderer_context)方法的结果,通常不需要自己调用.render(),因为它是由Django处理的​

rest_framework.request.Request和rest_framework.response.Response:​

drf的Request类扩展对标准的HttpRequest做了增强,使得更加灵活地request parsing请求解析和request authentication请求认证;​

drf的Request对象,允许使用JSON data或其它media types像通常处理表单数据一样处理请求;​

request.POST # Only handles form data. Only works for 'POST' method. 如form = PublisherForm(request.POST)​

request.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.​

包括所有解析的内容,file和non-file inputs;​

支持解析POST以外的HTTP method,如PUT|PATCH;​

更加灵活,不仅支持表单数据,传入同样JSON数据一样可正确解析,且不用做额外处理(即前端不管提交的是表单数据还是JSON数据,request.data都能正确解析);​

request.query_params #同request.GET,不过其名字更加容易理解,推荐使用request.query_params,使得更加明显地体现出任何HTTP method都可能包含query params,而不仅是GET请求​

request.parser #@api_view装饰器或APIView根据视图上设置的parser_classes或settings.py中DEFAULT_PARSER_CLASSES来确保此属性自动设置为Parser实例列表,不需要关注此属性,包含3个解析器,JSONParser|FormParser|MultiPartParser​

Response(data, status=None, template_name=None, headers=None, content_type=None)​

data #响应的序列化数据​

status #响应的状态码,默认200​

template_name #选择HTMLRenderer时使用的模板名称​

headers #字典类型​

content_type #响应的内容类型,通常渲染器会根据内容协商的结果自动设置,有时也要手动指定​

return Response(data) # Renders to content type as requested by the client.根据客户端的请求渲染内容类型​

属性​

.data #还没有渲染,但已经序列化的响应数据。​

.status_code #状态码​

.content #将会返回的响应内容,必须先调用 .render() 方法,才能访问 .content 。​

.template_name #只有在 response 的渲染器是 HTMLRenderer 或其他自定义模板渲染器时才需要提供。​

.accepted_renderer #用于将会返回的响应内容的渲染器实例。从视图返回响应之前由 APIView 或 @api_view 自动设置。​

.accepted_media_type #内容协商阶段选择的媒体类型,从视图返回响应之前由 APIView 或 @api_view 自动设置。​

.renderer_context #将传递给渲染器的 .render() 方法的附加的上下文信息字典。从视图返回响应之前由 APIView 或 @api_view 自动设置。​

标准 HttpResponse 属性​

Response 类扩展于 SimpleTemplateResponse,并且响应中也提供了所有常用的属性和方法。例如,您可以用标准方式在响应中设置 header:​

response = Response()​

response['Cache-Control'] = 'no-cache'​

.render() #与其他任何TemplateResponse一样,调用此方法将响应的序列化数据呈现为最终响应内容。响应内容将设置为在accepted_renderer 实例上调用 .render(data,accepted_media_type,renderer_context) 方法的结果。通常不需要自己调用 .render() ,因为它是由 Django 处理的。​

rest_framework.decorators.api_view和rest_framework.views.APIView:​

The @api_view decorator for working with function based views.​

The APIView class for working with class-based views.同django.views.View​

例,@api_view:​

@api_view(['GET', 'POST']) #只作为接口使用,用browser访问报WrappedAttributeError,'CSRFCheck' object has no attribute 'process_request'​

@csrf_exempt​

def author_list(request):​

if request.method == 'GET':​

authors = Author.objects.all()​

serializer = AuthorSerializer(authors, many=True)​

# return JSONResponse(serializer.data)​

# return JsonResponse(serializer.data, safe=False)​

return Response(serializer.data)​

elif request.method == 'POST':​

data = JSONParser().parse(request)​

serializer = AuthorSerializer(data=data)​

if serializer.is_valid():​

serializer.save()​

# return JsonResponse(serializer.data, status=201)​

return Response(serializer.data, status=201)​

# return JsonResponse(serializer.errors, status=400)​

return Response(serializer.errors, status=400)​

用postman测GET和POST;​

api CBV,rest_framework.views.APIView:​

例:​

from rest_framework.views import APIView​

from rest_framework import status​

from django.http import Http404​

class AuthorList(APIView):​

def get(self, request, format=None):​

authors = Author.objects.all()​

serializer = AuthorSerializer(authors, many=True)​

return Response(serializer.data)​

def post(self, request, format=None):​

serializer = AuthorSerializer(data=request.data)​

if serializer.is_valid():​

serializer.save()​

return Response(serializer.data, status=status.HTTP_201_CREATED)​

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)​

class AuthorDetail(APIView):​

def get_object(self, pk):​

try:​

return Author.objects.get(pk=pk)​

except Author.DoesNotExist:​

return Http404​

def get(self, request, pk, format=None):​

author = self.get_object(pk)​

serializer = AuthorSerializer(author)​

return Response(serializer.data)​

def put(self, request, pk, format=None):​

author = self.get_object(pk)​

serializer = AuthorSerializer(author, data=request.data)​

if serializer.is_valid():​

serializer.save()​

return Response(serializer.data)​

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)​

def delete(self, request, pk, format=None):​

author = self.get_object(pk)​

author.delete()​

return Response(status=status.HTTP_204_NO_CONTENT)​

# url(r'^authors/$', api.author_list, name='author_list'),​

url(r'^authors/$', AuthorList.as_view()),​

# url(r'^authors/(?P<pk>[0-9]+)/$', api.author_detail, name='author_detail'),​

url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetail.as_view()),​

api CBV,使用rest_framework.mixins:​

generics.GenericAPIView继承APIView,封装了很多方法,比APIView功能更强大;;在视图定义时,继承的各mixin,最后一个必须要为generics.GenericAPIView;​

用的时候需要定义queryset和serializer_class;​

mixins.ListModelMixin里的list方法做了分布和序列化工作,只需调用即可;​

mixins总共有5种:​

CreateModelMixin​

ListModelMixin​

UpdateModelMixin​

RetrieveModelMixin​

DestroyModelMixin​

例:​

from rest_framework import mixins​

from rest_framework import generics​

class AuthorList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

def get(self, request, *args, **kwargs):​

return self.list(request, *args, **kwargs)​

def post(self, request, *args, **kwargs):​

return self.create(request, *args, **kwargs)​

class AuthorDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

def get(self, request, *args, **kwargs):​

return self.retrieve(request, *args, **kwargs)​

def put(self, request, *args, **kwargs):​

return self.update(request, *args, **kwargs)​

def delete(self, request, *args, **kwargs):​

return self.destroy(request, *args, **kwargs)​

api CBV,ListAPIView|CreateAPIView|RetrieveAPIView|DestroyAPIView|UpdateAPIView|ListCreateAPIView​

generics.ListCreateAPIView​

generics.RetrieveUpdateDestroyAPIView:​

定义视图时,若继承下面这些,只需定义queryset和serializer_class,对应的方法已经写好了;​

class CreateAPIView(mixins.CreateModelMixin, #POST​

GenericAPIView):​

class ListAPIView(mixins.ListModelMixin, #GET​

GenericAPIView):​

class RetrieveAPIView(mixins.RetrieveModelMixin, #GET detail​

GenericAPIView):​

class DestroyAPIView(mixins.DestroyModelMixin, #DELETE​

GenericAPIView):​

class UpdateAPIView(mixins.UpdateModelMixin, #PUT PATCH​

GenericAPIView):​

class ListCreateAPIView(mixins.ListModelMixin, #GET POST​

mixins.CreateModelMixin,​

GenericAPIView):​

class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, #GET PUT PATCH​

mixins.UpdateModelMixin,​

GenericAPIView):​

class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, #GET DELETE​

mixins.DestroyModelMixin,​

GenericAPIView):​

class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, #GET PUT PATCH DELETE​

mixins.UpdateModelMixin,​

mixins.DestroyModelMixin,​

GenericAPIView):​

例:​

from rest_framework import generics​

class AuthorList(generics.ListCreateAPIView):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

class AuthorDetail(generics.RetrieveUpdateDestroyAPIView):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

DRF学习笔记(1)

postman测试时,PUT方法注意要用JSON;​

rest_framework.viewsets和rest_framework.routers.DefaultRouter:​

一般都是用viewsets;​

ViewSet类与View类其实几乎是相同的;​

ViewSet与View不同之处在于:​

ViewSet提供read或update之类的操作,而不是get或put等HTTP方法处理程序;​

ViewSet提供了默认的url结构,使得我们更专注于API本身;​

当它被实例化成一组视图的时候,通过使用Router类来处理自己定义的url,Router提供了一种简单|快速|集成的方式来定义一系列的urls;​

从低到高依次为:​

View #django,from django.views.generic.base import View或from django.views import View​

APIView #drf,from rest_framework.views import APIView​

GenericAPIView #drf,from rest_framework.generics import GenericAPIView​

GenericViewSet #drf,from rest_framework.viewsets import GenericViewSet​

注:​

# Note: Views are made CSRF exempt from within `as_view` as to prevent​

# accidental removal of this exemption in cases where `dispatch` needs to​

# be overridden.​

def dispatch(self, request, *args, **kwargs):​

"""​

`.dispatch()` is pretty much the same as Django's regular dispatch,​

but with extra hooks for startup, finalize, and exception handling.​

"""​

例:​

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):​

商品列表页'​

这里必须要定义一个默认的排序,否则会报错​

queryset = Goods.objects.all()​

分页​

pagination_class = GoodsPagination​

序列化​

serializer_class = GoodsSerializer​

filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)​

设置filter的类为我们自定义的类​

过滤​

filter_class = GoodsFilter​

搜索,=name表示精确搜索,也可以使用各种正则表达式​

search_fields = ('=name','goods_brief')​

排序​

ordering_fields = ('sold_num', 'add_time')​

例:​

from rest_framework import viewsets​

class AuthorViewSet(viewsets.ReadOnlyModelViewSet): #仅提供list和detail操作​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)​

例:​

from rest_framework import viewsets​

class AuthorViewSet(viewsets.ModelViewSet): #提供list|create|retrieve|update|destroy​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)​

author_list = AuthorViewSet.as_view({​

'get': 'list',​

'post': 'create'​

})​

author_detail = AuthorViewSet.as_view({​

'get': 'retrieve',​

'put': 'update',​

'pathch': 'partial_update',​

'delete': 'destroy',​

})​

# url(r'^authors/$', api.author_list, name='author_list'),​

# url(r'^authors/$', AuthorList.as_view()),​

url(r'^authors/$', author_list, name='author-list'),​

# url(r'^authors/(?P<pk>[0-9]+)/$', api.author_detail, name='author_detail'),​

# url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetail.as_view()),​

url(r'^authors/(?P<pk>[0-9]+)/$', author_detail, name='author-detail'),​

例,使用routers:​

from rest_framework import viewsets​

class AuthorViewSet(viewsets.ModelViewSet):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)​

router = DefaultRouter()​

router.register(r'authors', AuthorViewSet)​

urlpatterns = [​

……​

]​

urlpatterns += router.urls方式1​

# urlpatterns += [方式2​

# url(r'^', include(router.urls)),​

# ]​

分页:​

REST_FRAMEWORK = {​

# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',​

'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',​

"PAGE_SIZE": 2, ​

自定义分页:​

from rest_framework.pagination import PageNumberPagination​

class GoodsPagination(PageNumberPagination):​

'''​

商品列表自定义分页​

'''​

默认每页显示的个数​

page_size = 10​

可以动态改变每页显示的个数​

page_size_query_param = 'page_size'​

页码参数​

page_query_param = 'page'​

最多能显示多少页​

max_page_size = 100​

class GoodsListView(generics.ListAPIView):​

商品列表页'​

pagination_class = GoodsPagination分页​

queryset = Goods.objects.all()​

serializer_class = GoodsSerializer​

认证:​

源码流程:​

dispatch开始​

APIView中dispatch源码流程:​

request = self.initialize_request(request, *args, **kwargs) #1,对原生request进行加工,丰富了一些功能,获取原生request用request._request,获取认证类的对象用request.authenticators​

self.initial(request, *args, **kwargs) ,用self.perform_authentication(request)实现认证并调用request.user(获取认证对象进一步地认证,调用self._authenticate()循环认证对象若失败在此处抛异常)​

self.response = self.finalize_response(request, response, *args, **kwargs)​

DRF学习笔记(1)

认证成功或失败request.user和request.auth中会有值,失败的值可在配置文件中配置,没配置为None;​

如果只是使用:​

class MyAuthentication(BaseAuthentication): #第1步​

def authenticate(self, request):​

token = request._request.GET.get('token')​

#todo,获取用户名密码,去数据库校验​

token_obj = models.UserToken.objects.filter(token=token).first()​

if not token:​

raise exceptions.AuthenticationFailed('用户认证失败') #from rest_framework import exceptions​

#return ('jowin', None) 第1个元素给了request.user,第2个元素给了request.auth​

return (token_obj.user, token_obj)​

def authenticate_header(self, val): #该方法是认证失败时给b提供的响应头​

pass​

class DogView(APIView):​

authentication_classes = [MyAuthentication,] #第2步​

def get(self, request, *args, **kwargs):​

print(request.user)​

pass​

注:​

可局部定义直接用(上例);​

也可全局在settings.py中定义,在不需要用的类上写authentication_classes = []​

REST_FRAMEWORK = {​

'DEFAULT_AUTHENTICATION_CLASSES': ('utils.auth.FirstAuthentication','utils.auth.Authentication'),​

'UNAUTHENTICATED_USER': None, #request.user=None​

'UNAUTHENTICATED_TOKEN': None, #request.auth=None​

#'UNAUTHENTICATED_USER': lambda :'匿名用户'​

}​

注,生成token​

def md5(user):​

import hashlib​

import time​

ctime = str(time.time())​

m = hashlib.md5(bytes(user, encoding='utf-8'))​

m.update(bytes(ctime, encoding='utf-8'))​

return m.hexdigest()​

认证​

权限​

节流(访问频率控制)​

版本​

认证:​

问题1:有些api需用户登录成功后才能访问,有些无需登录就能访问​

解决:创建2张表;用户登录返回token并保存至DB​

class OrderView(APIView):​

''' '''​

def get(self, request, *args, **kwargs):​

ret = {'code': 1000, 'msg': None, 'data': None}​

try:​

ret['data'] = ORDER_DICT​

except Exception as e:​

pass​

return JsonResponse(ret)​

from rest_framework import authentication下默认提供了​

class BaseAuthentication 推荐使用,在自定义认证类时继承BaseAuthentication;​

class BasicAuthentication 将用户名密码加密后放到请求头中​

class SessionAuthentication​

class TokenAuthentication​

class RemoteUserAuthentication​

使用时:​

1创建类,继承BaseAuthentication,实现authenticate方法​

2返回值:​

None,我不管了,下一认证来执行;​

raise exceptions.AuthenticationFailed('用户认证失败'),from rest_framework import exceptions;​

(element1, element2),元素1赋值给request.user,元素2赋值给request.auth;​

3局部使用|全局使用​

4源码流程:​

dispatch-->​

封装request,获取定义的认证类(全局|局部),通过列表生成式创建对象-->​

initial,perform_authentication,request.user(内部循环)​

django支持认证方式:​

Basic,默认;​

Session;​

Token;​

自定义认证;​

DRF学习笔记(1)

默认用Basic认证,输入Username和Password,会自动生成到Headers中,用base64加密;​

DRF学习笔记(1)

例,使用token认证:​

INSTALLED_APPS = [​

'rest_framework.authtoken',​

REST_FRAMEWORK = {​

'DEFAULT_AUTHENTICATION_CLASSES': (​

# 'rest_framework.authentication.BasicAuthentication',​

# 'rest_framework.authentication.SessionAuthentication',​

'rest_framework.authentication.TokenAuthentication',​

)​

}​

(webproject) C:\webproject\mysite>python manage.py makemigrations​

(webproject) C:\webproject\mysite>python manage.py migrate​

>>> from django.contrib.auth.models import User​

>>> from rest_framework.authtoken.models import Token​

>>> t = Token.objects.create(user=User.objects.get(id=1))​

>>> t.key​

'219c0ec96617256b93b36d0ab95b70e7c893ac1b'​

DRF学习笔记(1)

例,用session认证:​

DRF学习笔记(1)

KEY中Cookie,VALUE中粘贴网页中Network中csrftoken;​

授权:​

​​https://www.django-rest-framework.org/api-guide/permissions/#api-reference​​​

rest_framework内置权限:​

AllowAny​

IsAuthenticated​

IsAdminUser​

IsAuthenticatedOrReadOnly​

DjangoModelPermissions​

DjangoModelPermissionsOrAnonReadOnly​

DjangoObjectPermissions​

REST_FRAMEWORK = {​

"PAGE_SIZE": 1,​

"DEFAULT_AUTHENTICATION_CLASSES": (​

# 'rest_framework.authentication.BasicAuthentication',​

# 'rest_framework.authentication.SessionAuthentication',​

'rest_framework.authentication.TokenAuthentication',​

'rest_framework.permissions.IsAuthenticated',全局配置默认权限​

)​

}​

例,view中使用权限控制:​

from rest_framework import generics​

from rest_framework import permissions​

class AuthorList(generics.ListCreateAPIView):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

permission_classes = (permissions.IsAuthenticated,) #多个是and的关系​

例,自定义权限:​

from rest_framework import generics​

from rest_framework import permissions​

class IsSuperUser(permissions.BasePermission): #继承permissions.BasePermission,重写has_permission()​

def has_permission(self, request, view):​

return request.user.is_superuser()​

class AuthorList(generics.ListCreateAPIView):​

queryset = Author.objects.all()​

serializer_class = AuthorSerializer​

# permission_classes = (permissions.IsAuthenticated,)​

permission_classes = (IsSuperUser,)​

面试题目:​

1、中间件​

2、csrf原理及解决,解决1cors(响应头放在中间件),解决2jsonp​

3、restful规范,10条谈,谈restful api规范的认识?10条,认识要与实际使用经验结合​

4、面向对象​

5、django请求生命周期​

6、django请求生命周期(包含rest_framework),dispatch()​

7、rest_framework,认证流程|权限流程|节流流程​

8、FBV|CBV​

面向对象:​

封装 将属性和方法封装到类中,2通过构造方法把一部分数据封装到对象里,之后打包使用​

继承 #若在2个类或多个类中有相同的属性和方法,可提取到1个类中实现;多继承,先左边后右边,广度优先|深度优先,经典类|新式类​

多态 #1个对象点出来什么,就具有什么方法或属性​

django请求生命周期(包含rest framework):​

wsgi-->​

中间件-->​

as_view中view中dispatch-->​

initialize_request()中封装request,get_parsers()获取解析器列表解析式,另get_authenticators()获取认证对象列表解析式-->​

initial()中determine_version()处理版本,另perform_authentication(request)|check_permissions(request)|check_throttles(request)-->​

反射执行对应HTTP方法​

各组件按生命周期:​

路由​

版本​

认证​

权限​

节流​

通过反射执行视图(继承...),用解析器拿到数据​

序列化,对数据校验并序列化​

分页​

渲染器​

另,wsgiref|werkzeug|tornado|uwsgi是实现wsgi协议的一个模块,本质是一个socket服务器;​

CBV​

基于反射实现,根据请求方法不同,执行不同的方法;​

流程:url-->view()-->dispatch()反射执行HTTP方法GET|POST|DELETE|PUT​

DRF学习笔记(1)

csrf​

基于中间件的process_view方法,装饰器@csrf_exempt(无需认证)或@csrf_protect(需认证)给单独函数进行设置;​

另,jsonp解决csrf;​

django csrf用中间件实现,1个中间件里最多可写5个方法:​

process_request​

process_view #csrf在此步验证的,1先检查函数是否@csrf_exempt,2去请求体中取cookie中的token​

process_response​

process_exception​

process_render_template​

使用中间件做过什么?适用于所有请求批量做操作​

基于角色的权限控制;​

用户登录验证;​

csrf; #process_view方法检查视图是否被@csrf_exempt,去请求体cookie里获取token​

session; ​

黑名单;​

日志记录;​

情况1:​

settings.py中配置了全局csrf;​

from django.views.decorators.csrf import csrf_exempt #@csrf_exempt被装饰的函数免除csrf验证​

情况2:​

settings.py中注释掉了csrf;​

from django.views.decorators.csrf import csrf_protect被装饰的函数启用csrf验证​

CBV中解决使用csrf:​

要用method_decorator(csrf_exempt),且要在dispatch上;​

from django.utils.decorator import method_decorator​

class StudentViews(View):​

@method_decorator(csrf_exempt) 方式1​

def dispatch(self, request, *args, **kwargs):​

return super(StudentView,self).dispatch(request, *args, **kwargs)​

def get(self, request, *args,**kwargs):​

print('get()')​

return HttpResponse('GET')​

@method_decorator(csrf_exempt, name='dispatch') #方式2​

class StudentViews(View):​

def get(self, request, *args,**kwargs):​

print('get()')​

return HttpResponse('GET')​

DRF学习笔记(1)
DRF学习笔记(1)

pip install djangorestframework​

权限​

源码流程:​

self.initial(request, *args, **kwargs) #dispatch中​

self.check_permissions(request) #initial中​

def check_permissions(self, request):​

"""​

Check if the request should be permitted.​

Raises an appropriate exception if the request is not permitted.​

"""​

for permission in self.get_permissions(): 循环执行每个权限对象的has_permission​

if not permission.has_permission(request, self):​

self.permission_denied(​

request, message=getattr(permission, 'message', None)​

)​

使用:​

1,类,必须继承BasePersmission,必须实现has_permission方法,一般不在此处抛异常,返回False就可做到;​

2,返回值:​

False #无权访问​

True #有权访问​

3,全局使用,settings.py中,REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES':['utils.permission.SVIPPermission',]} ,可在不需要权限的视图中加permission_classes=[]​

例,使用:​

utils/permission.py​

class MyPermission(BasePermission): 没有自定义的才找全局的​

message = '必须是SVIP才能访问'​

def has_permission(self, request, view):​

if request.user.user_type != 3:​

return False​

return True​

class MyPermission1(BasePermission):​

def has_permission(self, request, view):​

if request.user.user_type == 3:​

return False​

return True​

api/views.py​

from utils import permission​

class OrderView(APIView):​

permission_classes = [permission.MyPermission,]​

class UserInfoView(APIView):​

permission_classes = [permission.MyPermission1,]​

节流​

访问频率控制:​

内置方法:​

from rest_framework.throttlling import BaseThrottle #get_ident()获取remote_addr​

class SimpleRateThrottle(BaseThrottle)​

class AnonRateThrottle(SimpleRateThrottle)​

class UserRateThrottle(SimpleRateThrottle)​

class ScopedRateThrottle(SimpleRateThrottle)​

使用:​

1,类,继承BaseThrottle,实现allow_request和wait方法,​

类,继承SimpleThrottle,实现get_cache_key方法,scope='luffy'用作配置文件的key;​

2,全局使用|局部使用;​

utils/throttle.py​

VISIT_RECORD = {}​

class VisitThrottle(BaseThrottle):​

def __init__(self.):​

self.history = None​

def allow_request(self,request,view):​

#remote_addr = request.META.get('REMOTE_ADDR') #也可以request._request.META.get('REMOTE_ADDR')​

remote_addr = self.get_ident()​

ctime = time.time()​

if remote_addr not in VISIT_RECORD:​

VISIT_RECORD[remote_addr] = [ctime,]​

return True​

history = VISIT_RECORD.get(remote_addr)​

self.history = history​

while history and history[-1] < ctime - 60:​

history.pop()​

if len(history) < 3:​

history.insert(0, ctime)​

return True​

def wait(self): #还剩多少时间可访问​

ctime = time.time()​

return 60-(ctime-self.history[-1])​

class VisitThrottle(SimpleRateThrottle): #用于局部throttle_classes=[VisitThrottle,]​

scope = 'luffy' #匿名用户​

def get_cache_key(self, request, view):​

return self.get_ident(request)​

class UserThrottle(SimpleThrottle): 用于全局​

scope = 'luffyUser' #登录用户​

def get_cache_key(self, request, view):​

return request.user.username​

settings.py​

REST_FRAMEWORK = {​

'DEFAULT_THROTTLE_CLASSES':['utils.throttle.UserThrottle'],​

'DEFAULT_THROTTLE_RATES':{​

'luffy': '3/m', #1分钟3次​

'luffyUser': '10/m'​

},​

}​

版本,*​

解析器,*服务端判断是什么数据​

序列化,****重要,请求数据进行校验,QuerySet进行序列化​

分页,**​

路由,**​

视图,**​

渲染器,*​

DRF学习笔记(1)

版本​

1url中通过GET传参,​​http://127.0.0.1:8000/api/users/?versinotallow=v1​​,from rest_framework.versioning import QueryParameterVersioning​

2url路径中传参,http://127.0.0.1:8000/api/v1/users/,from rest_framework.versioning import URLPathVersioning,​

url(r'^api/', include('api.urls')) 根路由​

url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view(),name='uuu') #子路由​

REST_FRAMEWORK = { #settings.py​

"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",​

"DEFAULT_VERSION":"v1",​

"ALLOWED_VERSIONS":"['v1','v2']",​

"VERSION_PARAM":"version",​

}​

例,局部配置:​

class ParamVersion(BaseVersioning): #此类不需要自己写了,有现成的QueryParameterVersioning,from rest_framework.versioning import BaseVersioning​

def determine_version(self, request, *args, **kwargs):​

version = request.query_params.get('version')​

return version​

class UserView(APIView):​

#versioning_class = ParamVersion​

versioning_class = QueryParameterVersioning #versioning_class = URLPathVersioning​

def get (self, request,*args,**kwargs):​

print(request.version) #获取版本​

print(request.versioning_scheme) #获取处理版本的对象​

url1 = request.versioning_scheme.reverse(viewname='uuu',request=request) #反向生成url,rest_framework​

print(url1)​

url2 = reverse(viewname='uuu',kwargs={'version':2}) #反向生成url,django​

print(url2)​

return HttpResponse('用户列表')​

DRF学习笔记(1)

解析器:​

rest_framework解析器,对请求体数据进行解析,靠Content-Type对请求体中的数据解析;​

本质:请求头|状态码|请求方法;​

源码流程:​

django的​

request.body 请求体​

request.POST #从请求体中转为QueryDict​

from django.core.handlers.wsgi import WSGIRequest​

要保证request.POST中有值,必须满足2个:​

请求头要求,Content-Type: application/x-www-form-urlencoded,会去request.body中解析数据​

数据格式要求,name=alex&age=18&gender=man​

$.ajax({ #默认会将data转为name=alex&age=18,带上请求头Content-Type: application/x-www-form-urlencoded​

url:...​

type:POST,​

data:{name:alex,age=18}​

})​

$.ajax({ #默认会将data转为name=alex&age=18,带上请求头Content-Type: application/json,request.body中有值,request.POST没有,请求头不对​

url:...​

type:POST,​

headers: {'Content-Type':'application/json'},​

data:{name:alex,age=18}​

})​

$.ajax({ #请求头和data都不对,request.body中有值,request.POST没有​

url:...​

type:POST,​

headers: {'Content-Type':'application/json'},​

data:JSON.stringify({name:alex,age=18})​

})​

局部使用:​

from rest_framework.parsers import JSONParser​

class ParserView(APIView):​

parser_classes = [JSONParser,] 有JSONParser此view只能解析Content-Type是application/json的,另FormParser可解析Content-Type是application/x-www-form-urlencoded​

def post(self,request, *args, **kwargs):​

print(request.data)​

全局使用:​

REST_FRAMEWORK = {​

'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']​

}​

在视图中,request.data​

序列化​

对请求数据验证;queryset序列化;​

注1,django序列化,字段较多时一个个的提取很麻烦:​

for good in goods:​

json_dict = {}​

获取商品的每个字段,键值对形式​

json_dict['name'] = good.name​

json_dict['category'] = good.category.name​

json_dict['market_price'] = good.market_price​

json_list.append(json_dict)​

from django.http import HttpResponse​

import json​

#返回json,一定要指定类型content_type='application/json'​

return HttpResponse(json.dumps(json_list),content_type='application/json')​

注2,用model_to_dict,将model整个转化为dict,但ImageFieldFile和add_time字段不能序列化:​

from django.forms.models import model_to_dict​

for good in goods:​

json_dict = model_to_dict(good)​

json_list.append(json_dict)​

from django.http import HttpResponse​

import json​

#返回json,一定要指定类型content_type='application/json'​

return HttpResponse(json.dumps(json_list),content_type='application/json')​

注3,django的serializers:​

字段序列化定死的,要想重组很麻烦;​

images保存的是相对路径,还得补全路径,这些drf可帮我们做到;​

import json​

from django.core import serializers​

from django.http import JsonResponse​

json_data = serializers.serialize('json',goods)​

json_data = json.loads(json_data)​

#In order to allow non-dict objects to be serialized set the safe parameter to False.​

return JsonResponse(json_data,safe=False)​

序列化-序列化:​

使用:​

1定义类时,继承serializers.Serializer或serializers.ModelSerializer​

2字段,​

title = serializers.CharField(source='xxx.xxx.xxx'),source中的参数如果可执行会自动加();​

many=True表示queryset多条记录,many=False表示单个对象,实例化一般是将数据封装到对象;​

rls = serializers.SerializerMethodField(),还得定义get_rls();​

表中有choices和FK时,serializer里可通过source指定;​

而manytomany不能用source,没有这么细的粒度,使用serializers.SerializerMethodField()自定义显示;​

使用serializers.ModelSerializer,简单的直接在fields中指定,使得自动生成serializer字段,特殊的单独写;​

源码:​

对象,Serializer类处理;​

QuerySet,ListSerializer类处理;​

ser.data,ser为UserInfoSerializer实例;​

注,序列化对象,2个参数instance|多个对象many=True:​

def get(self,request,*args,**kwargs):​

users = models.UserInfo.objects.all()​

ser = UserInfoSerializer(instance=users,many=True)​

ret = json.dumps(ser.data,ensure_ascii=False)​

注,校验:​

def post(self,request,*args, **kwargs):​

ser = UserGroupSerializer(data=request.data)​

if ser.is_valid():​

print(ser.validated_data['title'])​

else:​

print(ser.errors)​

注,判断一个对象是否是函数:​

DRF学习笔记(1)

例1:​

DRF学习笔记(1)

json.dumps(roles, ensure_ascii=False)是为了在web页展示,ensure_ascii=False不对中文字符转换​

DRF学习笔记(1)

many=True表示多行记录QuerySet,many=False表示单个对象;​

例2-1:​

DRF学习笔记(1)

表中有choices和FK时,serializer里可通过source指定,source="get_user_type_display"会显示文本(而不是实际存储的数字);​

而manytomany不能用source,没有这么细的粒度,使用serializers.SerializerMethodField()自定义显示;​

DRF学习笔记(1)

自定义方法,用get_字段名;​

例2-2:​

表中有FK时,用category = CategorySerialzer(),可嵌套显示category分类信息,即json数据嵌套形式;​

class CategorySerializer(serializers.ModelSerializer):​

class Meta:​

model = GoodsCategory​

fields = "__all__"​

#ModelSerializer实现商品列表页​

class GoodsSerializer(serializers.ModelSerializer):​

覆盖外键字段​

category = CategorySerializer()​

class Meta:​

model = Goods​

fields = '__all__'​

例3:​

使用serializers.ModelSerializer,简单的直接在fields中指定使得自动生成serializer字段,特殊的单独写;​

DRF学习笔记(1)

例4:​

class UserInfoSerializer(serializers.ModelSerializer):​

class Meta:​

model = models.UserInfo​

fields = ['id', 'username', 'password', 'group', 'roles']​

depth = 1 #自动序列化连表,官方建议0-10,一般不要超过3​

DRF学习笔记(1)

例5:​

生成链接​

DRF学习笔记(1)

lookup_url_kwarg='xxx',xxx为url(r'^(?P<version>[v1|v2]+)/group/(?P<xxx>\d+)$',)​

例6:​

注:​

class LeavingMessageSerializer(serializers.ModelSerializer):​

'''​

用户留言​

'''​

# 获取当前登录的用户​

user = serializers.HiddenField(default=serializers.CurrentUserDefault())​

#read_only:只返回,post时候可以不用提交,format:格式化输出​

add_time = serializers.DateTimeField(read_notallow=True, format='%Y-%m-%d %H:%M')​

class Meta:​

model = UserLeavingMessage​

fields = ("user", "message_type", "subject", "message", "file", "id" ,"add_time")​

class LeavingMessageViewset(mixins.ListModelMixin, mixins.DestroyModelMixin, mixins.CreateModelMixin,viewsets.GenericViewSet):​

"""​

list:​

获取用户留言​

create:​

添加留言​

delete:​

删除留言功能​

"""​

permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)​

authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)​

serializer_class = LeavingMessageSerializer​

# 只能看到自己的留言​

def get_queryset(self):​

return UserLeavingMessage.objects.filter(user=self.request.user)​

序列化-请求数据校验:​

自定义验证规则时,需要钩子函数,钩子函数如何写?def validate_字段名(self, value)​

例1:​

DRF学习笔记(1)
DRF学习笔记(1)

class UserGroupView(APIView):​

def post(self,request,*args, **kwargs):​

ser = UserGroupSerializer(data=request.data)​

if ser.is_valid():​

print(ser.validated_data['title'])​

else:​

print(ser.errors)​

用户提交数据验证")​

例2:​

#自定义验证规则​

class GroupValidation(object):​

def __init__(self,base):​

self.base = base​

def __call__(self, value):​

if not value.startswith(self.base):​

标题必须以%s为开头"%self.base​

raise serializers.ValidationError(message)​

class UserGroupSerializer(serializers.Serializer):​

title = serializers.CharField(validators=[GroupValidation('以我开头'),]) ​

class UserGroupView(APIView):​

def post(self,request,*args, **kwargs):​

ser = UserGroupSerializer(data=request.data)​

if ser.is_valid():​

print(ser.validated_data['title'])​

else:​

print(ser.errors)​

用户提交数据验证")​

分页​

视图​

路由​

渲染​

django组件:contenttype​

渲染​

settings.py中INSTALLED_APPS中写上'rest_framework'​

使用时,在视图上return Response(se.data),from rest_framework.response import Response​

先序列化数据,再友好地展示;​

DRF学习笔记(1)

from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer, AdminRenderer​

全局用:​

REST_FRAMEWORK = {​

'DEFAULT_RENDERER_CLASSES':​

'rest_framework.renderers.JSONRenderer',​

'rest_framework.renderers.BrowsableAPIRenderer'​

}​

局部用:​

DRF学习笔记(1)

分页​

1看第n页,每页显示n条数据;​

2在某个位置,向后查看n条数据;​

3加密分页,上一页|下一页,内部记录id的最大值和最小值;​

from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination​

使用CursorPagination,要用pg.get_paginated_response(),next|previous可显示出来;​

例:​

class MyPageNumberPagination(PageNumberPagination):​

page_size = 2​

page_size_query_param = 'size' #http://127.0.0.1:8000/api/v1/pager1/?page=1&size=20 #size可自动调整,max_page_size控制最多显示多少条​

max_page_size = 5​

page_query_param = 'page'​

例1:​

DRF学习笔记(1)

例2:​

DRF学习笔记(1)
DRF学习笔记(1)

pg.get_paginated_response(ser.data),会自动生成返回值,且有上一页|下一页|count,前端没有要求可以不传;​

DRF学习笔记(1)

例3:​

DRF学习笔记(1)

视图​

View--> #class View(object):,django的,from django.views.generic import View​

APIView--> #class APIView(View):,from rest_framework.views import View, APIView​

GenericAPIView--> ,from rest_framework.generics import GenericAPIView,通常不用,还得重写get方法​

class GenericViewSet(ViewSetMixin, generics.GenericAPIView): #继承了2个,继承了ViewSetMixin,路由发生变化​

class ModelViewSet(mixins.CreateModelMixin, #继承了6个​

mixins.RetrieveModelMixin,​

mixins.UpdateModelMixin,​

mixins.DestroyModelMixin,​

mixins.ListModelMixin,​

GenericViewSet):​

class ListAPIView(mixins.ListModelMixin,继承了2个;2写了get方法;使用时仅需定义queryset和serializer_class​

GenericAPIView):​

"""​

Concrete view for listing a queryset.​

"""​

def get(self, request, *args, **kwargs):​

return self.list(request, *args, **kwargs)​

总结:​

增删改查 #ModelViewSet​

增删 #CreateModelMixin|DestroyModelMixin|GenericViewSet​

复杂逻辑 #GenericViewSet或APIView​

另,class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,​

mixins.ListModelMixin,​

GenericViewSet):​

ViewSet类与View类几乎相同,但提供的是read|update这些操作,而不是get|put等HTTP方法,同时ViewSet提供了默认的url结构,使得我们更专注于API本身;​

Router提供了一种简单|快速|集成的方式来定义一系列的urls;​

权限相关:​

DRF学习笔记(1)

例:​

DRF学习笔记(1)

例:​

DRF学习笔记(1)

例:​

DRF学习笔记(1)

路由​

手动要写4个url:​

DRF学习笔记(1)

增删改查,用自动生成;​

DRF学习笔记(1)

router = routers.DefaultRouter()​

router.regisnter(r'rt', views.View1View) #rt为该路由的前缀,会以这个前缀生成4个路由​

url(r'^(?P<version>[v1|v2]+)/', include(router.urls)) #r'^(?P<version>[v1|v2]+)/'为版本,没有版本为^​

DRF学习笔记(1)

content-type​

django内置的一个组件,帮助开发者做连表操作,FK|manytomany|onetoone,混搭(关联可以是任何类型);​

适用于1张表和多张表关联;​

DRF学习笔记(1)

例:​

DRF学习笔记(1)
DRF学习笔记(1)

drf的api文档自动生成:​

pip install coreapi​

from rest_framework.documentation import include_docs_urls​

urlpatterns = [​

文档,title自定义​

仙剑奇侠传')),​

]​

drf的api文档自动生成:​

优点:​

自动生成​

文档里可以做交互和测试​

可以生成js,shell和python代码段​

#drf文档,title自定义​

path('docs',include_docs_urls(title='仙剑奇侠传')),​

代码中注释格式:​

class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):​

'''​

list:​

商品列表,分页,搜索,过滤,排序​

retrieve:​

获取商品详情​

'''​

drf对象级别的权限支持:​

pip install django-guardian​

drf的过滤:​

例,如果不用django-filters,用name过滤,代码为:​

def get_queryset(self):​

queryset = Product.objects.all()​

name = self.request.query_params.get('name', None)​

if name is not None:​

queryset = queryset.filter(name=name)​

return queryset​

django-filters​

INSTALLED_APPS = [ 'django_filters', ]​

# goods/filters.py​

import django_filters​

from .models import Goods​

class GoodsFilter(django_filters.rest_framework.FilterSet):​

'''​

商品过滤的类​

'''​

#两个参数,field_name是要过滤的字段,lookup_expr是执行的行为,‘小于等于本店价格’​

price_min = django_filters.NumberFilter(field_name="shop_price",lookup_expr='gte')​

price_max = django_filters.NumberFilter(field_name="shop_price",lookup_expr='lte')​

top_category = django_filters.NumberFilter(field_name="category",method='top_category_filter')​

def top_category_filter(self, queryset, name, value):​

# 不管当前点击的是一级分类二级分类还是三级分类,都能找到。​

return queryset.filter(Q(category_id=value) |Q(category__parent_category_id=value) | Q(category__parent_category__parent_category_id=value))​

class Meta:​

model = Goods​

fields = ['price_min', 'price_max']​

# views.py​

from .filters import GoodsFilter​

from django_filters.rest_framework import DjangoFilterBackend​

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):​

#'商品列表页'​

#这里必须要定义一个默认的排序,否则会报错​

queryset = Goods.objects.all().order_by('id')​

# 分页​

pagination_class = GoodsPagination​

serializer_class = GoodsSerializer​

filter_backends = (DjangoFilterBackend,)​

# 设置filter的类为我们自定义的类​

filter_class = GoodsFilter​

​​http://127.0.0.1:8000/goods/?price_min=10&price_max=50​​​

使用方式1:​

class ClusterFilter(filters.FilterSet):​

class Meta:​

model = ClusterConf​

fields = ['cluster_name', 'cluster_type']​

class DbList(RestBase, generics.ListAPIView):​

serializer_class = Serializer​

queryset = ClusterConf.objects.all()​

filter_class = ClusterFilter​

使用方式2:​

class DbList(RestBase, generics.ListAPIView):​

serializer_class = Serializer​

queryset = ClusterConf.objects.all()​

filterset_fields = ['cluster_name', 'cluster_type']​

例,多IP查询:​

class ServerFilter(django_filters.rest_framework.FilterSet):​

ip_list = django_filters.rest_framework.BaseInFilter(field_name='ip', lookup_expr='in')​

hostname_list = django_filters.rest_framework.BaseInFilter(field_name='hostname', lookup_expr='in')​

class Meta:​

model = ResourceManage​

fields = ['ip_list', 'ip', 'hostname_list', 'app']​

drf的搜索和排序​

搜索的字段可用正则,更灵活;​

class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):​

'商品列表页'​

#这里必须要定义一个默认的排序,否则会报错​

queryset = Goods.objects.all().order_by('id')​

# 分页​

pagination_class = GoodsPagination​

serializer_class = GoodsSerializer​

filter_backends = (DjangoFilterBackend,filters.SearchFilter)​

# 设置filter的类为我们自定义的类​

filter_class = GoodsFilter​

#搜索,=name表示精确搜索,也可以使用各种正则表达式​

#search_fields = ('=name','goods_brief')​

search_fields = ('name', 'goods_brief', 'goods_desc')​

#ordering_fields = ('sold_num', 'add_time')​

ordering_fields = ('sold_num', 'shop_price')​

​​http://127.0.0.1:8000/goods/?ordering=-sold_num&search=水果​​​

例:​

from django_filters import rest_framework as filters​

from rest_framework import filters as filters_search​

from django_filters.rest_framework import DjangoFilterBackend​

class AppList(generics.ListCreateAPIView):​

db = AppConfig​

serializer_class = Serializer​

pagination_class = StandardResultsSetPagination​

filter_class = CFilter​

queryset = db.objects.all().order_by('id')​

filter_backends = (filters_search.SearchFilter, DjangoFilterBackend) # 在既有filter_class和search_fields时,此行必写​

search_fields = ('project_name__unit', 'project_name__plate', 'project_name__project_name',​

'project_name__subsystem_name',​

'pool_name__pool_cname', 'owner__user_name', 'app_name', 'app_type', 'app_descrip', 'app_lang',​

'app_arch', 'app_level', 'app_cname', 'package_type',​

'address')​

例,根据姓名模糊搜索AppConfig维护人(表中存的是工号):​

class CustomSearchFilter(SearchFilter):​

def get_search_terms(self, request):​

"""​

Search terms are set by a ?search=... query parameter,​

and may be comma and/or whitespace delimited.​

"""​

params = request.query_params.get(self.search_param, '')​

params = params.replace(',', ' ').split()​

lst = [i for i in params]​

for item in params:​

regex = re.compile(r'[\u4e00-\u9fa5]')​

if regex.match(item):​

uuids = [row.uuid for row in UserInfo.objects.filter(user_name=item)]​

for uuid in uuids:​

lst.append(uuid) if uuid else None​

return lst​

def filter_queryset(self, request, queryset, view):​

search_fields = self.get_search_fields(view, request)​

search_terms = self.get_search_terms(request)​

if not search_fields or not search_terms:​

return queryset​

orm_lookups = [​

self.construct_search(six.text_type(search_field))​

for search_field in search_fields​

]​

base = queryset​

conditions = []​

for search_term in search_terms:​

queries = [​

models.Q(**{orm_lookup: search_term})​

for orm_lookup in orm_lookups​

]​

conditions.append(reduce(operator.or_, queries))​

queryset = queryset.filter(reduce(operator.or_, conditions))​

if self.must_call_distinct(queryset, search_fields):​

# Filtering against a many-to-many field requires us to​

# call queryset.distinct() in order to avoid duplicate items​

# in the resulting queryset.​

# We try to avoid this if possible, for performance reasons.​

queryset = distinct(queryset, base)​

return queryset​

DRF学习笔记(1)
DRF学习笔记(1)

例,排序(django_filters.OrderingFilter):​

class Product(models.Model):​

name = models.CharField(max_length=100)​

created_at = models.DatetimeField()​

class ProductFilter(django_filters.FilterSet):​

sort = django_filters.OrderingFilter(fields=('created_at',))​

class Meta:​

model = Product​

fields = ['name',]​

使用时,前端用/products/?sort=-created_at​

例,排序(rest_framework.filters.OrderingFilter):​

# 在类视图中配置如下​

filter_backends = (OrderingFilter, )​

ordering_fields = ('create_time', 'price', 'sales')​

例,高级搜索:​

fields为list形式,则是按=严格匹配;​

fields为dict形式,可选择更多的匹配方式,如:​

模糊查询fields = {'name': ['icontains']},那么模糊查询的url则为/products/?name__icnotallow=xxx;​

日期范围查询,fields = {'name': ['icontains'], 'created_at': ['date__gte', 'date__lte']},url对应为/products/?created_at__date__gte=2019-11-20&created_at__date__lte=2019-11-22,​

这种方式定义的url所需参数太长,可自定义filter字段,如:​

class ProductFilter(django_filters.FilterSet):​

sort = django_filters.OrderingFilter(fields=('created_at',))​

min_date = django_filters.DateFilter(name='created_at__date', lookup_expr='gte')​

max_date = django_filters.DateFilter(name='created_at__date', lookup_expr='lte')​

class Meta:​

model = Product​

fields = {'name': ['icontains']}​

项目根下urls.py​

# MxShop/urls.py​

from django.urls import path,include,re_path​

import xadmin​

from django.views.static import serve​

from MxShop.settings import MEDIA_ROOT​

# from goods.view_base import GoodsListView​

from rest_framework.documentation import include_docs_urls​

from goods.views import GoodsListViewSet​

from rest_framework.routers import DefaultRouter​

router = DefaultRouter()​

#配置goods的url​

router.register(r'goods', GoodsListViewSet)​

router.register(r'categorys', CategoryViewSet, base_name="categorys")​

router.register(r'users', UserViewset, base_name="users")​

router.register(r'userfavs', UserFavViewset, base_name="userfavs")​

router.register(r'messages', LeavingMessageViewset, base_name="messages")​

router.register(r'shopcarts', ShoppingCartViewset, base_name="shopcarts")​

router.register(r'orders', OrderViewset, base_name="orders")​

router.register(r'indexgoods', IndexCategoryViewset, base_name="indexgoods")​

urlpatterns = [​

path('xadmin/', xadmin.site.urls),​

path('api-auth/',include('rest_framework.urls')),​

path('ueditor/',include('DjangoUeditor.urls' )),​

#文件​

path('media/<path:path>',serve,{'document_root':MEDIA_ROOT}),​

#drf文档,title自定义​

path('docs',include_docs_urls(title='仙剑奇侠传')),​

#商品列表页​

re_path('^', include(router.urls)),​

]​

drf的token​

缺点:​

保存在DB中,如果是一个分布式系统就非常麻烦;​

token永久有效,没有过期时间;​

INSTALLED_APPS = (​

...​

'rest_framework.authtoken'​

)​

from rest_framework.authtoken import views​

urlpatterns = [​

# token​

path('api-token-auth/', views.obtain_auth_token)​

]​

客户端身份验证:​

对于客户端进行身份验证,令牌密钥应包含在,关键字应以字符串文字,例如Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b​

注意:如果您想在header中使用不同的关键字(例如 Bearer),只需子类化TokenAuthentication并设置keyword类变量​

如果成功通过身份验证,TokenAuthentication将提供以下凭据:​

request.user #是一个Django User实例​

request.auth #是一个rest_framework.authtoken.models.Token实例​

未经身份验证的响应被拒绝将导致HTTP 401 Unauthorized的响应和相应的WWW-Authenticate header,例如:WWW-Authenticate: Token​

要想获取request.user和request.auth要在settings.py中添加​

REST_FRAMEWORK = {​

'DEFAULT_AUTHENTICATION_CLASSES': (​

'rest_framework.authentication.BasicAuthentication',​

'rest_framework.authentication.SessionAuthentication',​

'rest_framework.authentication.TokenAuthentication'​

)​

}​

jwt方式,用户认证​

pip install djangorestframework-jwt​

REST_FRAMEWORK = {​

'DEFAULT_PERMISSION_CLASSES': (​

'rest_framework.permissions.IsAuthenticated',​

),​

'DEFAULT_AUTHENTICATION_CLASSES': (​

'rest_framework.authentication.BasicAuthentication',​

'rest_framework.authentication.SessionAuthentication',​

'rest_framework.authentication.TokenAuthentication'​

)​

}​

import datetime​

#有效期限​

JWT_AUTH = {​

'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), #也可以设置secnotallow=20​

'JWT_AUTH_HEADER_PREFIX': 'JWT', #JWT跟前端保持一致,比如“token”这里设置成JWT​

}​

from rest_framework_jwt.views import obtain_jwt_token​

urlpatterns = [​

url(r'^api-token-auth/', obtain_jwt_token),​

url(r'^api-token-refresh/', refresh_jwt_token),​

url(r'^api-token-verify/', verify_jwt_token),​

]​

drf的缓存:​

pip install drf-extensions​

from rest_framework_extensions.cache.mixins import CacheResponseMixin​

class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, Mixins.RetrieveModelMixin,viewsets.GenericViewSet): #必须在第1个位置​

REST_FRAMEWORK_EXTENSIONS = {​

'DEFAULT_CACHE_RESPONSE_TIMEOUT': 5 #5s过期,时间自己可以随便设定​

}​

drf配置redis​

pip install django-redis​

# redis缓存​

CACHES = {​

"default": {​

"BACKEND": "django_redis.cache.RedisCache",​

"LOCATION": "redis://127.0.0.1:6379",​

"OPTIONS": {​

"CLIENT_CLASS": "django_redis.client.DefaultClient",​

}​

}​

}​

REST_FRAMEWORK = {​

#限速设置​

'DEFAULT_THROTTLE_CLASSES': (​

'rest_framework.throttling.AnonRateThrottle', #未登陆用户​

'rest_framework.throttling.UserRateThrottle' #登陆用户​

),​

'DEFAULT_THROTTLE_RATES': {​

'anon': '3/minute', #每分钟可以请求两次​

'user': '5/minute' #每分钟可以请求五次​

}​

}​

from rest_framework.throttling import UserRateThrottle,AnonRateThrottle​

class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):​

throttle_classes = (UserRateThrottle, AnonRateThrottle)​

social_django实现第三方登录​

pip install social-auth-app-django​

'socail-django' #INSTALLED_APP中引入​

python manage.py migrate #DB中多了5张表​

# 设置邮箱和用户名和手机号均可登录​

AUTHENTICATION_BACKENDS = (​

'users.views.CustomBackend',​

'social_core.backends.weibo.WeiboOAuth2',​

'social_core.backends.qq.QQOAuth2',​

'social_core.backends.weixin.WeixinOAuth2',​

'django.contrib.auth.backends.ModelBackend',​

)​

path('', include('social_django.urls', namespace='social'))​

DRF学习笔记(1)

Tokne的设计及加密方法​

Token的基本设计原则:Token不携带用户敏感信息;无需查询数据库,Token可进行自我验证;​

hmac作用,验证消息是否被篡改;公式;无法抵御重放gongji;​

hmac.new('secret123456', value).digest() # 加密密钥、value为加密的信息​

DRF学习笔记(1)