drf总结

  1 # models.py
  2 from django.db import models
  3 
  4 from django.contrib.auth.models import AbstractUser
  5 
  6 
  7 class User(AbstractUser):
  8     telephone = models.CharField(max_length=11)
  9     icon = models.ImageField(upload_to='icon', default='default.png')
 10 
 11 
 12 # class Book(models.Model):
 13 #     title = models.CharField(max_length=64)
 14 #     price = models.DecimalField(max_digits=5, decimal_places=2)
 15 #     sex = models.IntegerField(choices=((1, '男'), (2, '女')), blank=True, null=True)
 16 #     author = models.CharField(max_length=64)
 17 #     is_delete = models.BooleanField(default=False, blank=True, null=True)
 18 #
 19 #     def __str__(self):
 20 #         return self.get_sex_display()
 21 
 22 class BaseModels(models.Model):
 23     create_time = models.DateTimeField(auto_now_add=True)
 24     last_time = models.DateTimeField(auto_now=True)
 25     is_delete = models.BooleanField(default=False)
 26 
 27     class Meta:
 28         abstract = True
 29 
 30 
 31 class Book1(BaseModels):
 32     title = models.CharField(max_length=64)
 33     price = models.DecimalField(max_digits=5, decimal_places=2)
 34     author = models.ManyToManyField(to='Author', db_constraint=False)
 35     publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False)
 36 
 37     class Meta:
 38         verbose_name_plural = '书名'
 39 
 40     def __str__(self):
 41         return self.title
 42 
 43     @property
 44     def publish_name(self):
 45         return self.publish.name
 46 
 47     @property
 48     def author_list(self):
 49         author_list = self.author.all()
 50         li = []
 51         for author in author_list:
 52             li.append({'name': author.name, 'sex': author.get_sex_display()})
 53         return li
 54 
 55 
 56 class Publish(BaseModels):
 57     name = models.CharField(max_length=64)
 58     add = models.CharField(max_length=64)
 59 
 60     class Meta:
 61         verbose_name_plural = '出版社'
 62 
 63     def __str__(self):
 64         return self.name
 65 
 66 
 67 class Author(BaseModels):
 68     name = models.CharField(max_length=64)
 69     sex = models.IntegerField(choices=((1, ''), (2, '')))
 70     author_details = models.OneToOneField(to='AuthorDetails', db_constraint=False, on_delete=models.CASCADE)
 71 
 72     class Meta:
 73         verbose_name_plural = '作者'
 74 
 75     def __str__(self):
 76         return self.name
 77 
 78 
 79 class AuthorDetails(BaseModels):
 80     telephone = models.CharField(max_length=11)
 81 
 82     class Meta:
 83         verbose_name_plural = '作者详情'
 84 # urls.py
 85 from django.contrib import admin
 86 from django.urls import path, re_path, include
 87 from django.views.static import serve
 88 from django.conf import settings
 89 from rest_framework.routers import SimpleRouter
 90 from app01 import views
 91 
 92 router = SimpleRouter()
 93 # 群单 单增
 94 router.register('list_create', views.BookGenericViewSet, 'list_create')
 95 # 用户注册
 96 router.register('register', views.RegisterGenericViewSet, 'register')
 97 # # 单群改
 98 # router.register('', views.PutSGenericViewSet, 'puts')
 99 #
100 # router.register('', views.DeletesGenericViewSet, 'delete')
101 
102 # 群增
103 router.register('', views.PostsGenericViewSet, 'posts')
104 # 登录
105 router.register('', views.loginViewSet, 'login')
106 urlpatterns = [
107 
108     path('admin/', admin.site.urls),
109     # # 删除
110     path('deletes/', views.DeletesGenericViewSet.as_view()),
111     re_path(r'^deletes/(?P<pk>\d+)/$', views.DeletesGenericViewSet.as_view()),
112 
113     # # 单改群改
114     path('puts/', views.PutSGenericViewSet.as_view()),
115     re_path(r'^puts/(?P<pk>\d+)/$', views.PutSGenericViewSet.as_view()),
116 
117     # 头像
118     re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
119 
120     path('', include(router.urls)),
121 
122 ]
123 # views.py
124 from django.shortcuts import render
125 from rest_framework.views import APIView
126 from rest_framework.generics import GenericAPIView
127 from rest_framework.viewsets import ViewSet, GenericViewSet
128 from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin
129 
130 from rest_framework.response import Response
131 from rest_framework.decorators import action
132 
133 from rest_framework.filters import OrderingFilter
134 from django_filters.rest_framework import DjangoFilterBackend
135 from rest_framework.throttling import UserRateThrottle
136 
137 from . import models
138 from . import utils
139 from . import serializer
140 from .responses import comm_Response
141 
142 
143 # 登录
144 class loginViewSet(ViewSet):
145     @action(methods=['post'], detail=False)
146     def login(self, request, *args, **kwargs):
147         login_serializer = serializer.LoginModelSerializer(data=request.data)
148         if login_serializer.is_valid(raise_exception=True):
149             token = login_serializer.context['token']
150             username = login_serializer.context['user'].username
151             return Response(data={'code': 100, 'mag': '成功', 'token': token, 'username': username})
152         else:
153             return Response(data=login_serializer.errors)
154 
155 
156 # 注册接口
157 class RegisterGenericViewSet(GenericViewSet, CreateModelMixin):
158     queryset = models.User.objects.all()
159     serializer_class = serializer.RegisterModelSerializer
160 
161     # def create(self, request, *args, **kwargs):
162     #     response_data = self.get_serializer(request.data)
163 
164 
165 # book 单群查询 新增
166 class BookGenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin):
167     authentication_classes = [utils.comm_BaseAuthentication]
168 
169     permission_classes = [utils.comm_BasePermission]
170     # 内置可以和自定义混合使用
171     throttle_classes = [UserRateThrottle]
172     # 配置分页
173     pagination_class = utils.comm_PageNumberPagination
174     # filter_backends = [] # 过滤 排序text
175     filter_backends = [DjangoFilterBackend, OrderingFilter]
176     filter_fields = ('id', 'title')
177     ordering_fields = ('id',)
178 
179     queryset = models.Book1.objects.all().filter(is_delete=False)
180     serializer_class = serializer.BookModelSerializer
181 
182 
183 # 群增
184 # class PostsGenericViewSet(GenericAPIView):
185 class PostsGenericViewSet(GenericViewSet):
186     queryset = models.Book1.objects.all()
187     serializer_class = serializer.BookModelSerializer
188 
189     # 群增 
190     @action(methods=['post'], detail=False)
191     def posts(self, request, *args, **kwargs):
192         # book_serializer = serializer.BookModelSerializer(data=request.data, many=True)
193         book_serializer = self.serializer_class(data=request.data, many=True)
194         if book_serializer.is_valid():
195             book_serializer.save()
196             return comm_Response(code=100, msg='成功', data=book_serializer.data)
197         return comm_Response(code=0, msg='失败', data=book_serializer.errors)
198 
199 
200 # 单改 群改 # 手动配路由
201 class PutSGenericViewSet(GenericAPIView):
202     # queryset = models.Book1.objects.filter(is_delete=False)
203     queryset = models.Book1.objects.all()
204     serializer_class = serializer.BookModelSerializer
205 
206     def put(self, request, *args, **kwargs):
207         # 单改,
208         # 以pk判断 有为单改 无为群改
209         if kwargs.get('pk', None):
210             book = models.Book1.objects.filter(pk=kwargs.get('pk'), is_delete=False).first()
211             if book:
212                 book_serializer = serializer.BookModelSerializer(instance=book, data=request.data)
213                 if book_serializer.is_valid():
214                     book_serializer.save()
215                     return comm_Response(code=100, msg='成功', result=book_serializer.data)
216                 else:
217                     return comm_Response(code=0, msg='失败', result=book_serializer.errors)
218             else:
219                 return comm_Response(code=0, msg='该书已经删除,无法修改,请联系管理员处理')
220 
221         # 群改 [{'id':1,'name':cc},{}]---[{'name':cc},{}]
222         else:
223             if isinstance(request.data, list):
224                 # 前端传过来的数据
225                 books = []
226                 validates = []
227                 for dic in request.data:
228                     pk = dic.pop('id')
229                     book = models.Book1.objects.filter(pk=pk).first()
230                     books.append(book)
231                     validates.append(dic)
232                 book_serializer = serializer.BookModelSerializer(instance=books, data=validates, many=True)
233                 if book_serializer.is_valid():
234                     book_serializer.save()  # list 的save
235                     return comm_Response(code=100, msg='成功', result=book_serializer.data)
236 
237                 else:
238                     return comm_Response(code=0, msg='失败', result=book_serializer.errors)
239             else:
240                 return comm_Response(code=0, msg='失败,请按照格式传')
241 
242 # 删除 手动配路由
243 class DeletesGenericViewSet(APIView):
244 
245     def delete(self, request, *args, **kwargs):
246         pks = []
247         pk = kwargs.get('pk', None)
248         if pk:
249             pks.append(pk)
250         else:
251             pks = request.data.get('pk', None)
252         nums = models.Book1.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
253         if nums:
254             return comm_Response(code=100, msg='成功', nums=f'删除数据{nums}条')
255         else:
256             return comm_Response(code=0, msg='失败', nums=f'删除数据{nums}条')
257 
258 # response.py
259 from rest_framework.response import Response
260 
261 
262 class comm_Response(Response):
263     def __init__(self, result=None, code=None, msg='成功', status=None, headers=None, content_type=None, **kwargs):
264         dic = {
265             'msg': msg,
266             'code': code,
267         }
268         if result:
269             dic['result'] = result
270         dic.update(kwargs)
271         super(comm_Response, self).__init__(data=dic, status=status, headers=headers, content_type=content_type)
272 
273 # excetions.py
274 from rest_framework.views import exception_handler
275 from .responses import comm_Response
276 
277 
278 def comm_exception_handler(exc, context):
279     ret = exception_handler(exc, context)
280     if not ret:
281         if isinstance(exc, KeyError):
282             return comm_Response(code=0, result=str(exc), msg='key_error')
283         return comm_Response(code=0, result=str(exc), msg='error')
284     return comm_Response(code=0, result=ret.data, msg='error')
285 # utils.py
286 from rest_framework.authentication import BaseAuthentication
287 from rest_framework_jwt.serializers import jwt_decode_handler
288 from rest_framework.exceptions import AuthenticationFailed
289 from rest_framework.pagination import PageNumberPagination
290 
291 from . import models
292 import jwt
293 
294 # class comm_BaseAuthentication(BaseAuthentication):
295 #     def authenticate(self, request):
296 #         # 从头处获取Authentication
297 #         jwt_value = request.META.get('HTTP_AUTHORIZATION')
298 #         if jwt_value:
299 #             # 反解出user对象(不完整)
300 #             try:
301 #                 payload = jwt_decode_handler(jwt_value)
302 #             # payload--user
303 #             # print(payload)
304 #             # return payload, jwt_value
305 #             # 1.查库 or User对象i
306 #             except jwt.ExpiredSignature:
307 #                 raise AuthenticationFailed('签名过期')
308 #             except jwt.InvalidTokenError:
309 #                 raise AuthenticationFailed('用户非法')
310 #             except Exception as e:
311 #                 # 所有异常都会走到这
312 #                 raise AuthenticationFailed(str(e))
313 #             ret = models.User(id=payload.get('user_id'), username=payload.get('username'))
314 #             if ret:
315 #                 return ret, payload
316 #             else:
317 #                 raise AuthenticationFailed('用户不存在')
318 #         else:
319 #             raise AuthenticationFailed('没有携带token')
320 
321 from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication  # 基于它
322 
323 
324 # jwt 认证
325 class comm_BaseAuthentication(BaseJSONWebTokenAuthentication):
326     def authenticate(self, request):
327         # 从头处获取Authentication
328         jwt_value = request.META.get('HTTP_AUTHORIZATION')
329         if jwt_value:
330             # 反解出user对象(不完整)
331             try:
332                 payload = jwt_decode_handler(jwt_value)
333             # payload--user
334             # print(payload)
335             # return payload, jwt_value
336             # 1.查库 or User对象i
337             except jwt.ExpiredSignature:
338                 raise AuthenticationFailed('签名过期')
339             except jwt.InvalidTokenError:
340                 raise AuthenticationFailed('用户非法')
341             except Exception as e:
342                 # 所有异常都会走到这
343                 raise AuthenticationFailed(str(e))
344             user = self.authenticate_credentials(payload)
345             # user--对象
346             # print(user)
347             return user, payload
348         else:
349             raise AuthenticationFailed('没有携带token')
350 
351 
352 # 分页
353 class comm_PageNumberPagination(PageNumberPagination):
354     page_size = 10  # 每页条数
355     page_query_param = 'page'  # 查询第几页的key
356     page_size_query_param = 'size'  # 每一页显示的条数
357     max_page_size = 5  # 每页最大显示条数
358 
359 
360 # 权限
361 from rest_framework.permissions import BasePermission
362 
363 
364 class comm_BasePermission(BasePermission):
365 
366     def has_permission(self, request, view):
367         user = request.user
368         if not user.is_staff == 1:
369             raise AuthenticationFailed('没有权限,请付费观看')
370         return True
371 
372 
373 # 频率限制
374 from rest_framework.throttling import SimpleRateThrottle
375 
376 
377 # 自定义的逻辑
378 # (1)取出访问者ip
379 # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
380 # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
381 # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
382 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
383 class MyThrottles():
384     VISIT_RECORD = {}
385 
386     def __init__(self):
387         self.history = None
388 
389     def allow_request(self, request, view):
390         # (1)取出访问者ip
391         # print(request.META)
392         ip = request.META.get('REMOTE_ADDR')
393         import time
394         ctime = time.time()
395         # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
396         if ip not in self.VISIT_RECORD:
397             self.VISIT_RECORD[ip] = [ctime, ]
398             return True
399         self.history = self.VISIT_RECORD.get(ip)
400         # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
401         while self.history and ctime - self.history[-1] > 60:
402             self.history.pop()
403         # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
404         # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
405         if len(self.history) < 3:
406             self.history.insert(0, ctime)
407             return True
408         else:
409             return False
410 
411     def wait(self):
412         import time
413         ctime = time.time()
414         return 60 - (ctime - self.history[-1])
415 
416 # serializer.py 
417 from rest_framework import serializers
418 from . import models
419 
420 import re
421 import uuid
422 from rest_framework.exceptions import ValidationError
423 from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler
424 
425 
426 # 多方式登录--手机号 邮箱 账号
427 class LoginModelSerializer(serializers.ModelSerializer):
428     username = serializers.CharField()
429 
430     class Meta:
431         model = models.User
432         fields = ['username', 'password']
433         extra_kwargs = {
434             'password': {'write_only': True},
435             'username': {'read_only': True}
436         }
437 
438     def validate(self, attrs):
439         user = self._get_user(attrs)
440         token = self._get_token(user)
441         self.context['user'] = user
442         self.context['token'] = token
443         return attrs
444 
445     def _get_user(self, attrs):
446         username = attrs.get('username')
447         if re.match('^1[3-9][0-9]{9}$', username):
448             user = models.User.objects.filter(telephone=username).first()
449         elif re.match(r'^[1-9]\d{7,10}@qq\.com$', username):
450             user = models.User.objects.filter(email=username).first()
451         else:
452             user = models.User.objects.filter(username=username).first()
453         if user:
454             password = attrs.get('password')
455             ret = user.check_password(password)
456             if ret:
457                 return user
458             else:
459                 raise ValidationError('密码错误')
460         else:
461             ValidationError('用户不存在')
462 
463     def _get_token(self, user):
464         payload = jwt_payload_handler(user)
465         token = jwt_encode_handler(payload)
466         return token
467 
468 
469 # 注册
470 class RegisterModelSerializer(serializers.ModelSerializer):
471     re_password = serializers.CharField(write_only=True)
472 
473     class Meta:
474         model = models.User
475         fields = ['username', 'password', 're_password']
476         extra_kwargs = {
477             # 're_password': {'write_only': True},
478             'username': {'read_only': True}
479         }
480 
481     def validate(self, attrs):
482         password = attrs.get('password')
483         re_password = attrs.get('re_password')
484         username = attrs.get('username')
485         if password == re_password:
486             ret = models.User.objects.filter(username=username).first()
487             if not ret:
488                 attrs.pop('re_password')
489                 username = uuid.uuid4()
490                 attrs['username'] = username
491                 return attrs
492             else:
493                 raise ValidationError('用户已经注册')
494         else:
495             raise ValidationError('两次密码输入不一致')
496 
497     def create(self, validated_data):
498         print(validated_data)
499         # validated_data.pop('validated_data')
500         user = models.User.objects.create_user(**validated_data)
501         return user
502 
503 
504 # 重写update
505 class BookListSerializer(serializers.ListSerializer):
506     def update(self, instance, validated_data):
507         return [
508             self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
509         ]
510 
511 
512 #
513 class BookModelSerializer(serializers.ModelSerializer):
514     class Meta:
515         model = models.Book1
516         fields = ['id', 'title', 'price', 'publish', 'publish_name', 'author', 'author_list']
517         # depth=1
518         list_serializer_class = BookListSerializer
519         extra_kwargs = {
520             'publish': {'write_only': True},
521             'publish_name': {'read_only': True},
522             'author': {'write_only': True},
523             'author_list': {'read_only': True},
524             'id': {'read_only': True},
525         }
526 
527 # admin.py
528 from django.contrib import admin
529 from . import models
530 
531 admin.site.register(models.Book1)
532 admin.site.register(models.Publish)
533 admin.site.register(models.Author)
534 admin.site.register(models.AuthorDetails)
535 admin.site.register(models.User)
536 
537 # settings.py
538 INSTALLED_APPS = [
539     
540     'app01.apps.App01Config',
541     'rest_framework',
542     'rest_framework_jwt',
543     'django_filters',
544 ]
545 
546 LANGUAGE_CODE = 'zh-hans'
547 
548 TIME_ZONE = 'Asia/shanghai'
549 
550 USE_I18N = True
551 
552 USE_L10N = True
553 
554 USE_TZ = False
555 
556 # Static files (CSS, JavaScript, Images)
557 # https://docs.djangoproject.com/en/2.2/howto/static-files/
558 
559 STATIC_URL = '/static/'
560 
561 # 图像
562 MEDIA_URL = '/media/'
563 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
564 # user表
565 AUTH_USER_MODEL = 'app01.user'
566 
567 import datetime
568 
569 JWT_AUTH = {
570     # 过期时间1天
571     'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
572     # 自定义认证结果:见下方序列化user和自定义response
573     # 如果不自定义,返回的格式是固定的,只有token字段
574     # 'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
575 }
576 
577 # 全局异常
578 REST_FRAMEWORK = {
579     'EXCEPTION_HANDLER': 'app01.exception.comm_exception_handler',
580     'DEFAULT_THROTTLE_RATES': {
581         'user': '5/m'
582     }
583 
584 }

 

posted @ 2021-05-28 23:23  mofr  阅读(97)  评论(0)    收藏  举报