rest_framework(纯后端操作组件)中的各种插件方法
restful协议需要在这里码出来,不能仅仅是贴一个地址就作罢......
restful规范的理解
其实就是一套编写接口的协议,协议规定如何编写以及如何设置返回值,状态码等信息
最显著的特点:restful给用户一个url,根据method的不同在后端做不同的处理,比如post是创建数据,get获取数据,put和patch修改数据,delete是删除数据等
如果没有restful的话我们这些method请求不同,要分别设置与之对应的url,比如add_class/delete_class/post_class/get_class/
这里还有其他的比如版本,我们的程序有的时候会有版本迭代,会出现两个版本共存的情况,就需要加以区分,版本可以放到url,请求头(accept/自定义)
未完待续...
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
restful 这里具体解释了我们的面相资源编程的特点
我们的django里面都是前端和后端绑定在一起操作的,针对数据库进行增删改查操作,然后把数据渲染到页面上,交给浏览器显示给用户,供用户操作,
在vue里面我们的一切前端页面操作都是独立的,跟我们的django分开了,脱离后端,纯粹的前端,实现解耦.
在rest_framework里面,我们的一切操作都是纯粹的后端,不跟前端有任何瓜葛,实现解耦.
我们的django里面前端和后端要耦合一个关键的点是,我们的django生命请求周期里面,url跟view视图还有HTML模板是一整套流程,彼此胶合在一起,不可拆分,我们的url里面正则匹配上之后就会执行后面对应的view视图,然后在视图里面处理逻辑代码之后,就会把数据传给HTML模板,然后交给浏览器进行渲染,显示给我们的用户.
但是我们在rest_framework里面就不是这样的,它是一个组件,专门服务于后端使用,它主要的核心就是面相资源编程,这里我们引入了一个新的概念,面相资源编程,之前接触的都是面相对象编程和面相过程编程,
这个面相资源就是指我们所面对的一切数据都视作资源,它的核心的点就是把我们的url请求给拆分了,我们在django里面都是习惯了把一个url发送出去之后,在我们的HTML模板里面的标签来区分是post请求还是get请求,然后再由我们的视图来根据不同的请求处理数据,但是在我们的面向资源变成里面则不是这样的,一个url,我们在rest_framework里面把它拆分成更多的分支,如下即是
这是从源码里面摘出来的:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
这一段是我们从源码里面摘出来的,所有的请求都是在这个列表里面,当然了,我们主要用的就是get/post居多,再就是delete,
我们的每一条url都指定到具体的请求类型从上面的列表里面选取仅限于列表里面的类型,然后在访问url的时候,我们除了输入ur就可以
直接取出数据,post请求就直接提交数据,然后再具体的请求下面进行具体操作.
这样我们就不需要使用HTML前端模板来决定这条url是什么请求了,就可以从根源上跟我们的前端彻底脱离,实现功能解耦.
这里需要一个协助的工具,postman,它就是充当我们的浏览器自带渲染页面,让我们在开发阶段使用起来更加直观能看到效果,
我们要用的话需要在电脑上下载,
url的请求方式被拆分之后,紧接着我们就可以在里面给它加上参数了,比如我们的数据分页,比如我们的filter过滤等等,一样是使用&分割多个条件,也需要?进行区分,
基本上整个流程就是这样的,所以我们使用rest_framework的时候就不会写前端页面,那我们要跟前端实现数据交互的话,就需要通过一个json字符串来发送数据,我们把view视图里面的逻辑代码完成之后,返回值一律改成Response字符串,前端部分会有VUE通过ajax来接收后端的json字符串.
这里需要补充的点是我们的rest_framework的前身是CBV===>class basic view 基于类的视图
所以我们的url后面不是FBV(function basic view)而是一个类,基于类的视图,所以我们要了解rest_framework就需要对CBV有一定了解
点进去看 摘自yuanxiansheng博客
效果图附上,会更加直观:
这里就是postman的界面:
这里的流程我们再梳理一遍,其实我们的rest_framework的流程都是基于RESTful规范来的,
restful是什么呢?
官方说法是:REST代表的是一种软件架构风格,是Representational State Transfer的简称,中文翻译为"表征状态转移",
这里需要把restful的流程给补充完整......未完待续
rest_framework下载步骤:
使用cmd命令行============>>pip install rest_framework
下载之后,就可以使用编辑器启动项目了,
代码如下:

1 """ 2 Django settings for rest_test project. 3 4 Generated by 'django-admin startproject' using Django 1.11.9. 5 6 For more information on this file, see 7 https://docs.djangoproject.com/en/1.11/topics/settings/ 8 9 For the full list of settings and their values, see 10 https://docs.djangoproject.com/en/1.11/ref/settings/ 11 """ 12 13 import os 14 15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 18 # Quick-start development settings - unsuitable for production 19 # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 20 21 # SECURITY WARNING: keep the secret key used in production secret! 22 SECRET_KEY = 'pxf)9)k2j1@62yq4a!7s(in5i*p9c#18zb-mh6h-)oxg7u4-o^' 23 24 # SECURITY WARNING: don't run with debug turned on in production! 25 DEBUG = True 26 27 ALLOWED_HOSTS = [] 28 29 # Application definition 30 31 INSTALLED_APPS = [ 32 'django.contrib.admin', 33 'django.contrib.auth', 34 'django.contrib.contenttypes', 35 'django.contrib.sessions', 36 'django.contrib.messages', 37 'django.contrib.staticfiles', 38 'demo.apps.DemoConfig', 39 'rest_framework', 40 'api.apps.ApiConfig', 41 'tiny.apps.TinyConfig', 42 ] 43 44 MIDDLEWARE = [ 45 'django.middleware.security.SecurityMiddleware', 46 'django.contrib.sessions.middleware.SessionMiddleware', 47 'django.middleware.common.CommonMiddleware', 48 'django.middleware.csrf.CsrfViewMiddleware', 49 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 'django.contrib.messages.middleware.MessageMiddleware', 51 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 ] 53 54 ROOT_URLCONF = 'rest_test.urls' 55 56 TEMPLATES = [ 57 { 58 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 'DIRS': [os.path.join(BASE_DIR, 'templates')] 60 , 61 'APP_DIRS': True, 62 'OPTIONS': { 63 'context_processors': [ 64 'django.template.context_processors.debug', 65 'django.template.context_processors.request', 66 'django.contrib.auth.context_processors.auth', 67 'django.contrib.messages.context_processors.messages', 68 ], 69 }, 70 }, 71 ] 72 73 WSGI_APPLICATION = 'rest_test.wsgi.application' 74 75 # Database 76 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 77 78 DATABASES = { 79 'default': { 80 'ENGINE': 'django.db.backends.sqlite3', 81 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 82 } 83 } 84 85 # Password validation 86 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 87 88 AUTH_PASSWORD_VALIDATORS = [ 89 { 90 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 91 }, 92 { 93 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 94 }, 95 { 96 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 97 }, 98 { 99 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 100 }, 101 ] 102 103 # Internationalization 104 # https://docs.djangoproject.com/en/1.11/topics/i18n/ 105 106 LANGUAGE_CODE = 'en-us' 107 108 TIME_ZONE = 'UTC' 109 110 USE_I18N = True 111 112 USE_L10N = True 113 114 USE_TZ = True 115 116 # Static files (CSS, JavaScript, Images) 117 # https://docs.djangoproject.com/en/1.11/howto/static-files/ 118 119 STATIC_URL = '/static/' 120 121 # 这里是全局配置,我们按照源码里面的流程写的,我们自己有自己定义的参数就按照我们自己的参数走,否则,就走源码里面默认的参数, 122 REST_FRAMEWORK = { 123 "DEFAULT_AUTHENTICATION_CLASSES": ["api.service.auth.MyAuthentication"], # 登录验证 124 "DEFAULT_PERMISSION_CLASSES": ["api.service.permission.VIPPermission"], # 权限验证 125 "DEFAULT_THROTTLE_CLASSES": ["api.service.throttling.MyThrottle"], # 频率验证 126 # "DEFAULT_THROTTLE_RATES": {"xxx": "4/m"}, 127 "PAGE_SIZE": 2 128 }

1 """rest_test URL Configuration 2 3 The `urlpatterns` list routes URLs to views. For more information please see: 4 https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 Examples: 6 Function views 7 1. Add an import: from my_app import views 8 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 Class-based views 10 1. Add an import: from other_app.views import Home 11 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 Including another URLconf 13 1. Import the include() function: from django.conf.urls import url, include 14 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 """ 16 from django.contrib import admin 17 from django.conf.urls import url, include 18 from rest_framework import routers 19 from demo import views 20 from api import views as apiviews 21 from tiny import views as tinyviews 22 23 router = routers.DefaultRouter() # 这里是类实例化出来的对象,router就是我们的对象,它去调用类里面的url方法,自动生成url路由 24 router.register(r'users', views.UserViewSet) 25 router.register(r'groups', views.GroupViewSet) 26 router.register(r'publish', views.PublishViewSet) 27 28 router.register(r'books', apiviews.BookViewSet) 29 # Wire up our API using automatic URL routing. 30 # Additionally, we include login URLs for the browsable API. 31 urlpatterns = [ 32 # 这里是quickstart里面用到的两个url 33 # url(r'^', include(router.urls)), 34 # url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), 35 # ============================================================================================ 36 37 38 # url(r'^publishes/$', apiviews.PublishView.as_view(), name='publish_list'), 39 # url(r'^publishes/(?P<pk>\d+)/$', apiviews.PublishDetailView.as_view(), name='publish_detail'), 40 # 41 # url(r'^books/$', apiviews.BookView.as_view(), name='book_list'), 42 # url(r'^books/(?P<pk>\d+)/$', apiviews.BookDetailView.as_view(), name='book_detail'), 43 44 url(r'', include(router.urls)), # 它会自动给我们生成4个url, 45 # 我们这里boks开头的两个url是在我们上面的books基础上进行升级的,我们让两个url都走同一个视图, 46 # 然后在这个视图的基础上进行数据的分发,使用键值对的方式进行分发,这样我们的每一个请求过来都可以走到指定的函数方法里面 47 # url(r'^boks/$', apiviews.BookViewSet.as_view({'get': 'list', 'post': 'create'}), name='book_list'), 48 # url(r'^boks/(?P<pk>\d+)/$', apiviews.BookViewSet.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update'}), 49 # name='book_detail'), 50 # 51 url(r'^pub/$', apiviews.PublishViewSet.as_view({'get': 'list', 'post': 'create'}), name='publish_list'), 52 url(r'^pub/(?P<pk>\d+)', apiviews.PublishViewSet.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update'}), name='publish_detail'), 53 54 55 url(r'^admin', admin.site.urls), 56 url(r'^foo/$', tinyviews.foo), 57 url(r'^index/$', tinyviews.Index.as_view()), 58 59 url(r'^login/$', apiviews.LoginView.as_view()), 60 61 ]

1 from django.db import models 2 3 4 # Create your models here. 5 class Book(models.Model): 6 title = models.CharField(max_length=32) 7 price = models.IntegerField() 8 pub_date = models.DateField() 9 publish = models.ForeignKey('Publish') 10 authors = models.ManyToManyField('Author') 11 12 def __str__(self): 13 return self.title 14 15 16 class Publish(models.Model): 17 name = models.CharField(max_length=32) 18 email = models.EmailField() 19 20 def __str__(self): 21 return self.name 22 23 24 class Author(models.Model): 25 name = models.CharField(max_length=32) 26 age = models.IntegerField() 27 28 def __str__(self): 29 return self.name 30 31 32 class User(models.Model): 33 user = models.CharField(max_length=32) 34 pwd = models.CharField(max_length=32) 35 user_type = models.IntegerField(choices=((1, 'normal_customer'), (2, 'higher_customer'), (3, 'top_level_customer')), 36 default=1) 37 38 39 class UserToken(models.Model): 40 user = models.OneToOneField(to='User') 41 token = models.CharField(max_length=128)

1 from django.shortcuts import render 2 3 # Create your views here. 4 from rest_framework.views import APIView 5 import json 6 from .models import * 7 from rest_framework.response import Response 8 from rest_framework import mixins 9 from rest_framework import generics 10 from api.service.serializers import * 11 from api.service.permission import VIPPermission 12 from api.service.auth import MyAuthentication 13 from api.service.throttling import MyThrottle 14 from api.service.pagination import MyPageNumber 15 # 这里是相应器 16 from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer 17 18 # 这里是解析器,rest_framework里面有4种解析器, 19 from rest_framework.parsers import JSONParser, FormParser, FileUploadParser, MultiPartParser 20 21 # class BookView(APIView): 22 # """ 23 # 我们的CBV里面的方法不是可以随便写的,是有指定范围的, 24 # http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] 25 # 以上这个列表是源码里面摘出来的,该列表里面的方法都可以在CBV里面使用,只有这个列表里面的方法才可以. 26 # """ 27 # 28 # def get(self, request, *args, **kwargs): 29 # book_list = Book.objects.all() 30 # # 方式一 31 # # book_list=list(Book.objects.all().values('title','price')) 32 # # 方式二 33 # # temp=[] 34 # # for book in book_list: 35 # # temp.append({ 36 # # 'title':book.pk, 37 # # 'price':book.price, 38 # # 'pub_date':book.pub_date, 39 # # }) 40 # # 方式三 41 # # from django.core import serializers 42 # # temp=serializers.serialize('json',book_list) 43 # # return HttpResponse(temp) 44 # # 方式四 45 # # 将book_list转换成json数据[{},{},{}] 46 # bs = BookSerializers(book_list, many=True, context={'request': request}) 47 # # many默认是false,我们把queryset数据集合直接放到这里就可以把数据转换成json数据, 48 # # BookSerializers有两个参数,第一个是数据,第二个是many值,many默认是false,第一个参数的数据默认是一个单独的数据对象, 49 # # 第一个参数也可以是是数据集合,如果是集合的话就是多个值,many值需要改为True, 50 # # print(bs.data) # 序列化的结果 51 # """ 52 # [ 53 # OrderedDict( 54 # [('id', 1), 55 # ('authors', 56 # [{'pk': 1, 'name': 'Eval'}] 57 # ), 58 # ('title', 'python'), 59 # ('price', 23), 60 # ('pub_date', '2018-02-07'), 61 # ('publish', 1)]), 62 # OrderedDict( 63 # [('id', 2), 64 # ('authors', 65 # [ 66 # {'pk': 1, 'name': 'Eval'} 67 # ]), 68 # ('title', 'java开发实战'), 69 # ('price', 39), 70 # ('pub_date', '2017-11-22'), 71 # ('publish', 2)]), 72 # OrderedDict([ 73 # ('id', 3), 74 # ('authors', 75 # [ 76 # {'pk': 2, 'name': 'aliven'}, 77 # {'pk': 1, 'name': 'Eval'} 78 # ]), 79 # ('title', '百年孤独'), 80 # ('price', 79), 81 # ('pub_date', '2018-01-10'), 82 # ('publish', 2)]), 83 # OrderedDict([('id', 4), 84 # ('authors', [ 85 # {'pk': 2, 'name': 'aliven'}, {'pk': 3, 'name': 'egon'} 86 # ]), 87 # ('title', 'sound of music'), 88 # ('price', 35), 89 # ('pub_date', '2017-05-24'), 90 # ('publish', 1) 91 # ]) 92 # ] 93 # """ 94 # 95 # return Response(bs.data) 96 97 # # 98 # def post(self, request, *args, **kwargs): 99 # bs = BookSerializers(data=request.data, context={'request': request}) 100 # if bs.is_valid(): 101 # bs.save() 102 # return Response(bs.data) 103 # else: 104 # return Response(bs.errors) 105 106 107 # 108 # 109 # """ 110 # class BookSerializers(serializers.Serializer): 111 # title=serializers.CharField(max_length=32) 112 # price=serializers.IntegerField() 113 # pub_date=serializers.DateField() 114 # publish=serializers.CharField(source='publish.pk') 115 # authors=serializers.CharField() 116 # temp=[] 117 # for book in book_list: 118 # temp.append({ 119 # 'title':book.title, 120 # 'price':book.price, 121 # 'pub_date':book.publish.pk, 122 # 'authors':book.authors, 123 # }) 124 # 125 # [ 126 # { 127 # 'title':'python', 128 # 'price':45, 129 # 'publish':'1' 130 # }, 131 # { 132 # 'title':'go', 133 # 'price':89, 134 # 'publish':'2' 135 # } 136 # ] 137 # """ 138 # 139 140 # class BookDetailView(APIView): 141 # def get(self, request, id, *args, **kwargs): 142 # obj = Book.objects.filter(pk=id).first() 143 # if obj: 144 # res = BookSerializers(obj, context={'request': request}) 145 # return Response(res.data) 146 # else: 147 # return Response() 148 # 149 # def delete(self, request, id, *args, **kwargs): 150 # Book.objects.filter(pk=id).delete() 151 # return Response() 152 # 153 # def put(self, request, id, *args, **kwargs): 154 # obj = Book.objects.filter(pk=id).first() 155 # res = BookSerializers(data=request.data, instance=obj, context={'request': request}) 156 # if res.is_valid(): 157 # return Response(res.data) 158 # else: 159 # return Response(res.errors) 160 161 162 # =====================mixin=================== 163 """ 164 # 这里是我们的mixins方法构建的视图 165 166 class BookView(mixins.ListModelMixin, 167 mixins.CreateModelMixin, 168 generics.GenericAPIView): 169 queryset = Book.objects.all() 170 serializer_class = BookSerializers 171 172 def get(self, request, *args, **kwargs): 173 return self.list(request, *args, **kwargs) 174 175 def post(self, request, *args, **kwargs): 176 return self.create(request, *args, **kwargs) 177 178 179 class BookDetailView( 180 mixins.RetrieveModelMixin, 181 mixins.DestroyModelMixin, 182 mixins.UpdateModelMixin, 183 generics.GenericAPIView 184 ): 185 queryset = Book.objects.all() 186 serializer_class = BookSerializers 187 188 def get(self, request, *args, **kwargs): 189 return self.retrieve(request, *args, **kwargs) 190 191 def delete(self, request, *args, **kwargs): 192 return self.destroy(request, *args, **kwargs) 193 194 def put(self, request, *args, **kwargs): 195 return self.update(request, *args, **kwargs) 196 197 198 class PublishView(mixins.ListModelMixin, 199 mixins.CreateModelMixin, 200 generics.GenericAPIView): 201 queryset = Publish.objects.all() 202 serializer_class = PublishSerializers 203 204 def get(self, request, *args, **kwargs): 205 return self.list(request, *args, **kwargs) 206 207 def post(self, request, *args, **kwargs): 208 return self.create(request, *args, **kwargs) 209 210 211 class PublishDetailView( 212 mixins.RetrieveModelMixin, 213 mixins.DestroyModelMixin, 214 mixins.UpdateModelMixin, 215 generics.GenericAPIView 216 ): 217 queryset = Publish.objects.all() 218 serializer_class = PublishSerializers 219 220 def get(self, request, *args, **kwargs): 221 return self.retrieve(request, *args, **kwargs) 222 223 def delete(self, request, *args, **kwargs): 224 return self.destroy(request, *args, **kwargs) 225 226 def put(self, request, *args, **kwargs): 227 return self.update(request, *args, **kwargs) 228 """ 229 230 231 class BookView(generics.ListCreateAPIView): 232 queryset = Book.objects.all() 233 serializer_class = BookSerializers 234 235 236 class BookDetailView(generics.RetrieveUpdateDestroyAPIView): 237 queryset = Book.objects.all() 238 # print(1, args, 2, kwargs) 239 # 1()2{'pk': '5'} 240 serializer_class = BookSerializers 241 242 243 class PublishView(generics.ListCreateAPIView): 244 queryset = Publish.objects.all() 245 serializer_class = PublishSerializers 246 247 248 class PublishDetailView(generics.RetrieveUpdateDestroyAPIView): 249 queryset = Publish.objects.all() 250 serializer_class = PublishSerializers 251 252 253 # 这里就真的是终极版了.....有与之匹配的url 254 from rest_framework.viewsets import ModelViewSet 255 256 257 # 我们加在类里面的都是局部验证,全局验证都是在我们的setting.py配置文件里面的 258 class BookViewSet(ModelViewSet): 259 # authentication_classes = [MyAuthentication] # 登录验证 260 # permission_classes = [VIPPermission] # 权限验证 261 # throttle_classes = [MyThrottle, ] # 这里是频率验证 262 # pagination_class = MyPageNumber # 这里因为是分页我们只有一个,所以就不需要列表了,否则会报错 263 queryset = Book.objects.all() 264 serializer_class = BookSerializers 265 parser_classes = [JSONParser, FormParser, MultiPartParser] # 解析器验证 266 # renderer_classes = [BrowsableAPIRenderer, JSONRenderer] # 相应器验证 267 268 269 class PublishViewSet(ModelViewSet): 270 # authentication_classes = [MyAuthentication] 271 # permission_classes = [VIPPermission] 272 queryset = Publish.objects.all() 273 serializer_class = PublishSerializers 274 parser_classes = [FormParser] 275 276 277 from .models import * 278 from django.http import JsonResponse 279 280 281 # 这里是获取随机生成的字符串,随着时间的不同,它会随时变换,把时间和md5都加进去 282 def get_random_str(user): 283 import hashlib, time 284 ctime = str(time.time()) 285 286 md = hashlib.md5(bytes(user, encoding='utf8')) 287 md.update(bytes(ctime, encoding='utf8')) 288 289 return md.hexdigest() 290 291 292 # 登录,用于验证的CBV 293 class LoginView(APIView): 294 def post(self, request, *args, **kwargs): 295 user = request.data.get("user") 296 pwd = request.data.get('pwd') 297 user = User.objects.filter(user=user, pwd=pwd).first() 298 res = {"state_code": 200, "msg": None} 299 if user: 300 random_str = get_random_str(user.user) 301 user_token_obj = UserToken.objects.update_or_create(user=user, defaults={'token': random_str}) 302 res['msg'] = 'success' 303 res['token'] = random_str 304 else: 305 res['msg'] = 'user or pwd is wrong!' 306 res['state_code'] = 10086 307 return JsonResponse(res)
在view视图中我们都可以继承哪些类:
如图所示:
接下来就是我们的配置文件在django项目里面主逻辑的App里面建立一个文件夹,里面放上我们的配置文件:

1 from rest_framework import exceptions 2 from ..models import * 3 from rest_framework.authentication import BaseAuthentication 4 5 6 class MyAuthentication(BaseAuthentication): 7 def authenticate(self, request): 8 token = request._request.GET.get('token') 9 user_token_obj = UserToken.objects.filter(token=token).first() 10 if user_token_obj: 11 return user_token_obj.user, token 12 else: 13 raise exceptions.AuthenticationFailed('sorry no permission!')

1 from rest_framework.permissions import BasePermission 2 3 4 class VIPPermission(BasePermission): 5 message = 'you have not got permission!' 6 7 def has_permission(self, request, view): 8 if request.user.user_type == 3: 9 return True 10 else: 11 return False

1 from rest_framework import serializers # 序列化器,主要作用是把数据序列化 2 from ..models import * 3 4 5 class BookSerializers(serializers.ModelSerializer): 6 # 这里是把我们的外键关联字段变成a标签,有超链接,可以点击就跳转到相应的页面 7 # publish = serializers.HyperlinkedIdentityField( 8 # view_name='publish_detail', # 这里的view_name就是反向解析的名字,也就是我们写到url里面的那个名字 9 # lookup_field='publish_id', # 这里是我们所要设置成a标签超链接的字段名字 10 # lookup_url_kwarg='pk' # 这里是关键字我们在url里面加上的关键字参数,它跟我们反向解析的url里面的有名分组一样的名字,要对应上, 11 # 我们的超链接a标签里面的这些参数都是根据我们的url来进行反向解析的,第一个参数name就是反向解析的名字 12 # 第三个参数url_kwarg是我们的url里面的正则匹配的有名分组, 13 # 第二个参数是我们的这个正则匹配有名分组所对应的值,我们是根据id值去匹配的,那么我们直接从对象里面把id取出来即可, 14 # url(r'^publishes/(?P<pk>\d+)/$', apiviews.PublishDetailView.as_view(), name='publish_detail'), 15 # publishes/(?<pk>\d+)/$ 16 # ) 17 18 class Meta: 19 model = Book 20 fields = "__all__" 21 # 这里有两种写法,上面使用__all__得到的数据效果是这样的 22 """ 23 [ 24 { 25 "id": 1, 26 "authors": [ 27 { 28 "pk": 1, 29 "name": "Eval" 30 } 31 ], 32 "title": "python", 33 "price": 23, 34 "pub_date": "2018-02-07", 35 "publish": 1 36 }, 37 { 38 "id": 2, 39 "authors": [ 40 { 41 "pk": 1, 42 "name": "Eval" 43 } 44 ], 45 "title": "java开发实战", 46 "price": 39, 47 "pub_date": "2017-11-22", 48 "publish": 2 49 }, 50 { 51 "id": 3, 52 "authors": [ 53 { 54 "pk": 2, 55 "name": "aliven" 56 }, 57 { 58 "pk": 1, 59 "name": "Eval" 60 } 61 ], 62 "title": "百年孤独", 63 "price": 79, 64 "pub_date": "2018-01-10", 65 "publish": 2 66 }, 67 { 68 "id": 4, 69 "authors": [ 70 { 71 "pk": 2, 72 "name": "aliven" 73 }, 74 { 75 "pk": 3, 76 "name": "egon" 77 } 78 ], 79 "title": "sound of music", 80 "price": 35, 81 "pub_date": "2017-05-24", 82 "publish": 1 83 } 84 ] 85 """ 86 # 我们的exclude方法里面,不需要authors,以及下面的get_authors函数方法 87 # exclude = ['authors', ] 88 """ 89 这里是使用exclude方法取到的数据 90 { 91 "id": 1, 92 "title": "python", 93 "price": 23, 94 "pub_date": "2018-02-07", 95 "publish": 1 96 }, 97 { 98 "id": 2, 99 "title": "java开发实战", 100 "price": 39, 101 "pub_date": "2017-11-22", 102 "publish": 2 103 }, 104 { 105 "id": 3, 106 "title": "百年孤独", 107 "price": 79, 108 "pub_date": "2018-01-10", 109 "publish": 2 110 }, 111 { 112 "id": 4, 113 "title": "sound of music", 114 "price": 35, 115 "pub_date": "2017-05-24", 116 "publish": 1 117 } 118 ] 119 """ 120 121 authors = serializers.SerializerMethodField() 122 123 def get_authors(self, obj): 124 # print('obj>>>>>',obj) 125 """ 126 obj是我们这个表里的所有数据的__str__反射的字段名 127 obj>>>>> python 128 obj>>>>> java开发实战 129 obj>>>>> 百年孤独 130 obj>>>>> sound of music 131 """ 132 temp = [] 133 for author in obj.authors.all(): 134 temp.append({'pk': author.pk, 'name': author.name}) 135 return temp 136 137 138 class PublishSerializers(serializers.ModelSerializer): 139 class Meta: 140 model = Publish 141 fields = "__all__"

1 from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination,CursorPagination 2 3 4 # 这里我们自定义一个类然后继承我们的父类PageNumberPagination,然后把它里面的属性拿出来我们在这里重新定义,就可以得到我们自定义的效果, 5 # 就相当于是使用它的方法,然后按照我们自定义的参数来实现我们的效果 6 class MyPageNumber(PageNumberPagination): 7 page_size = 1 8 page_query_param = 'per_page' 9 page_size_query_description = 'length' 10 max_page_size = 2

1 from rest_framework.throttling import BaseThrottle, SimpleRateThrottle 2 from rest_framework.exceptions import APIException 3 import time 4 5 6 # 这里是我们自己写的,throttle 7 vist_dic = {} 8 9 10 class MyThrottle(BaseThrottle): 11 def __init__(self): 12 self.history = None 13 14 """ 15 我们要设置访问频率,就需要先把数据类型整理出来,要设置在一分钟之内对该url的访问不得超过3次的话, 16 需要考虑到用户是否已经登录的状态,每一个用户唯一的标识就是ip地址,以键值对的格式,ip为键,访问时间为值, 17 以列表的形式存起来,然后把不符合条件的时间删除,把符合条件的时间给添加到该列表里面,保证列表里面只有3个值 18 """ 19 20 # 我们从throttle里面的源码看到这个allow_request最终的返回值是bool值,所以我们照着写同样要把返回值写成bool值 21 def allow_request(self, request, view): 22 # 获取到用户的ip地址 23 # remote_addr=self.get_ident(request) # 这里是调用我们的父类BaseThrottle里面的方法 24 remote_addr = request.META.get('REMOTE_ADDR') 25 xff = request.META.get('HTTP_X_FORWARDED_FOR') 26 print("xff",xff,type(xff)) # xff None <class 'NoneType'> 27 ctime = time.time() # 获取当前时间 28 29 # 当第一次访问来临时我们就直接把时间放到列表里面去 30 if remote_addr not in vist_dic: # 判断该ip地址是否在我们的这个字典里面 31 vist_dic[remote_addr] = [ctime] # 然后把访问时间放到字典里面作为值 32 return True 33 self.history = vist_dic[remote_addr] 34 # print(self.history) # 这里的history就是存储我们的每一次访问的有效时间,就是从我们的vist_dic里面把存储的 35 # 有效时间拿出来放到这里来了, 36 """ 37 [1523431104.138973, 1523431101.737836, 1523431096.8755577] 38 这里打印出来的就是我们的有效访问时间, 39 """ 40 41 # 当第2,3次访问来临时,我们就需要判断请求的间隔时间了 42 if len(vist_dic[remote_addr]) < 3: # 判断列表的长度 43 vist_dic[remote_addr].insert(0, ctime) # 把最新的访问时间永远插入到列表里面的索引为0的地方 44 # print(vist_dic) 45 """ 46 {'127.0.0.1': [ 47 1523431321.6974168, 48 1523431320.898371, 49 1523431320.044322 50 ]} 51 """ 52 53 return True 54 55 if ctime - vist_dic[remote_addr][-1] > 60: 56 """ 57 这里是根据我们的限制条件,每一分钟里面同一个ip地址可以访问3次,来进行判断, 58 把不符合条件的访问时间给删除,然后把符合条件的访问时间给添加到列表里面去 59 """ 60 vist_dic[remote_addr].insert(0, ctime) 61 vist_dic[remote_addr].pop() 62 63 return False 64 65 def wait(self): 66 # 源码里面有这个wait方法, 67 """ 68 显示给用户还需要多长时间才可以访问, 69 :return:"detail": "Request was throttled. Expected available in 35 seconds." 70 """ 71 ctime = time.time() 72 return 60 - (ctime - self.history[-1]) 73 74 75 # 这里是更加简单的写法直接继承父类,然后调用即可 76 # class MyThrottle(SimpleRateThrottle): 77 # scope = 'xxx' 78 # 79 # def get_cache_key(self, request, view): 80 # return self.get_ident(request)
流程图:
=======================================================================================================================================