关闭页面特效

drf学习笔记

0|1drf主要内容


序列化Serializer、视图集ViewSet、路由router、认证authentication、权限permission

RESTful API

前端 == HTTP Method ==> 后端 后端 == Json/XML/YAML ==> 前端
restful api 实践

协议、域名、版本github api v3、路径(url)、http动作(rest)、过滤信息(Filtering)、状态码(status codes)、错误处理(Error handling)、返回结果、Hypermedia API

步骤

​ 配置 ==> 数据库对象 ==> 序列化 ==> 视图 ==> 路由 ==> 添加定制验证,权限

django默认序列化问题

  • 验证处理request.data
  • 验证器参数
  • 同时序列化多个对象
  • 序列化过程中添加上下文
  • 无效数据的异常处理

环境搭建

​ django-admin startproject drf-toturial
​ python manage.py startapp course
​ python manage.py makemigrations
​ python manage.py migrate
​ python manage.py createsuperuser --email example@qq.com

DRF配置

# drf_toturial/settings.py INSTALLED_APPS = { "...", "rest_framework", # RESTful API "rest_framework.authtoken", # Token 验证使用 } # DRF 全局设置 REST_FRAMEWORK = { "DEFAULT_PAGINATION_CLASSES": "rest_framework.pagination.PageNumberPagination", "PAGE_SIZE": 50, "DATE_FORMAT": "%y-%m-%d %H:%M:%S", "DEFAULT_RENDERER_CLASSES": [ "rest_framework.renderers.JSONRenderer", "rest_framework.renderers.BrowsableAPIRenderer", ], "DEFAULT_PARSER_CLASSES": [ "rest_framework.parsers.JSONParser", "rest_framework.parsers.FormParser", "rest_framework.parsers.MultiPartParser", ], "DEFAULT_PERMISSION_CLASSES": [ "rest_framework.permissions.IsAuthenticated", ], "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.BasicAuthentication", "rest_framework.authentication.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", ] }

json方法

方法 作用
json.dumps() 将Python对象转换为JSON字符串
json.dump() 将Python对象写入json文件
json.load() 从json文件中读取数据
json.loads() 将JSON字符串转换为Python对象dict

Models 操作数据库对象

# course/models.py from django.db import models from django.conf import settings # Create your models here. class Course(models.Model): name = models.CharField(max_length=255, unique=True, help_text='课程名称', verbose_name='名称') introduction = models.TextField(help_text='课程介绍', verbose_name='介绍') teacher = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, help_text='课程讲师', verbose_name='讲师') price = models.DecimalField(max_digits=6, decimal_places=2, help_text='课程价格', verbose_name='价格') created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间') class Meta: verbose_name = '课程信息' verbose_name_plural = verbose_name ordering = ['price', ] def __str__(self): return self.name ''' 有了django.core.serializers为什么还要使用djangorestframework 1. 验证数据 request.data 2. 验证器参数 3. 同时序列化多个对象 4. 序列化过程中添加上下文 5. 无效数据的异常处理 ''' # course/admin.py from django.contrib import admin # Register your models here. from .models import Course @admin.register(Course) class CourseAdmin(admin.ModelAdmin): list_display = ('name', 'introduction', 'teacher', 'price') search_fields = list_display list_filter = list_display

Serializers 序列化

  1. 继承模型序列化 models.ModelSerializer

  2. 超链接模型序列化 models.HyperLinkedModelSerializer

    from django import forms from rest_framework import serializers from .models import Course from django.contrib.auth.models import User class CourseForm(forms.ModelForm): class Meta: model = Course fields = ('name', 'introduction', 'teacher', 'price') class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = '__all__' # class CourseSerializer(serializers.ModelSerializer): # # teacher = serializers.ReadOnlyField(source='teacher.username') # 外键字段 只读 # # class Meta: # model = Course # # exclude = ('id', ) # 注意元组只一个元素时不能写成('id') # # fields = ('id', 'name', 'introduction', 'teacher', 'price', 'created_at', 'updated_at') # fields = '__all__' # # depth = 2 class CourseSerializer(serializers.HyperlinkedModelSerializer): teacher = serializers.ReadOnlyField(source='teacher.username') class Meta: model = Course # url为默认值,可在settings.py设置URL_FIELD_NAME使全局生效 fields = ('id', 'url', 'name', 'introduction', 'teacher', 'price', 'created_at', 'updated_at') def create(self, validated_data): # 生成对象 pass def to_representation(self, instance): # 重新定义序列化的数据 pass def to_internal_value(self, data): # 重新定义反序列化数据 pass

ViewSet 视图

视图开发: 分页、排序、认证、权限、限流

  1. 函数式视图

  2. 类视图

  3. 通用类视图

  4. 视图集

    # 示例: 两大类型 ## 1. FBV 和 CBV import json # Create your views here. from django.http import JsonResponse, HttpResponse # 导入返回包 from django.views.decorators.csrf import csrf_exempt # 取消POST方法的csrf限制 法1 from django.utils.decorators import method_decorator # 装饰器中的装饰方法 from django.views import View course_dict = { "name": "Vue3+Django4全新技术实战全栈项目", "introduction": "前后端分离模式,从开发到上线,带你系统提升全栈技能,收获企业级上线项目实战经验", "price": 299.00, } # 1. FBV 函数式视图 @csrf_exempt def course_list(request): if request.method == "GET": # return HttpResponse(json.dumps(course_dict), content_type="application/json") return JsonResponse(course_dict) if request.method == "POST": course = json.loads(request.body.decode('utf-8')) return JsonResponse(course, safe=False) # return HttpResponse(json.loads(request.body.decode('utf-8')), content_type="application/json") # 2. CBV 类视图 @method_decorator(csrf_exempt, name='dispatch') # django先到达dispatch方法再到达post方法 class CourseList(View): def get(self, request): return JsonResponse(course_dict) # @csrf_exempt # 1. 取消post csrf限制 def post(self, request): course = json.loads(request.body.decode('utf-8')) return JsonResponse(course, safe=False)

    实现

    # views.py # 1. 函数式视图 Function Based View # 2. 类视图 Classed Based View # 3. 通用类视图 Generic Classed Based View # 4. 视图集 ViewSets from rest_framework.decorators import api_view # 函数式api视图 from rest_framework.response import Response from rest_framework import status from rest_framework.views import APIView from rest_framework import generics from rest_framework import viewsets from .models import Course from .serializers import CourseSerializer # 1. FBV @api_view(['GET', 'POST']) def course_list(request): """ 获取所有课程; 新增一个课程 :param request: :return: """ if request.method == 'GET': s = CourseSerializer(Course.objects.all(), many=True) return Response(s.data, status.HTTP_200_OK) if request.method == 'POST': s = CourseSerializer(data=request.data) # 部分更新用partial=True属性 if s.is_valid(): s.save(teacher=request.user) return Response(s.data, status.HTTP_201_CREATED) return Response(s.errors, status.HTTP_400_BAD_REQUEST) @api_view(['GET', 'PUT', 'DELETE']) def course_detail(request, pk): """ 获取所有匹配详情; 更新信息; 删除信息 :param request: :param pk: :return: """ try: course = Course.objects.get(pk=pk) # get/first是一条信息,all,filter是多条信息 except Course.DoesNotExist: return Response(data={"msg": "未找到课程信息"}, status=status.HTTP_404_NOT_FOUND) else: if request.method == 'GET': s = CourseSerializer(instance=course) return Response(data=s.data, status=status.HTTP_200_OK) elif request.method == 'PUT': s = CourseSerializer(instance=course, data=request.data) if s.is_valid(): s.save() return Response(data=s.data, status=status.HTTP_200_OK) elif request.method == 'DELETE': course.delete() return Response(status=status.HTTP_204_NO_CONTENT) # 2. CBV class CourseList(APIView): def get(self, request): """ :param request: :return: """ queryset = Course.objects.all() s = CourseSerializer(instance=queryset, many=True) return Response(s.data, status.HTTP_200_OK) def post(self, request): """ :param request: :return: """ s = CourseSerializer(data=request.data) if s.is_valid(): s.save(teacher=request.user) # print(type(request.data), type(s.data)) # <class 'dict'> <class 'rest_framework.utils.serializer_helpers.ReturnDict'> return Response(s.data, status.HTTP_201_CREATED) return Response(s.errors, status.HTTP_400_BAD_REQUEST) class CourseDetail(APIView): @staticmethod # 供调用 def get_object(pk): """ :param pk: :return: """ try: return Course.objects.get(pk=pk) except Course.DoesNotExist: return def get(self, request, pk): """ :param request: :param pk: :return: """ obj = self.get_object(pk=pk) if not obj: return Response(data={"msg": "未找到课程信息"}, status=status.HTTP_404_NOT_FOUND) s = CourseSerializer(instance=obj) return Response(s.data, status=status.HTTP_200_OK) def put(self, request, pk): """ :param request: :param pk: :return: """ obj = self.get_object(pk=pk) if not obj: return Response(data={"msg": "未找到课程信息"}, status=status.HTTP_404_NOT_FOUND) s = CourseSerializer(instance=obj, data=request.data) if s.is_valid(): s.save() return Response(s.data, status=status.HTTP_201_CREATED) return Response(s.errors, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, pk): """ :param request: :param pk: :return: """ obj = self.get_object(pk=pk) if not obj: return Response(data={"msg": "未找到课程信息"}, status=status.HTTP_404_NOT_FOUND) obj.delete() return Response(status=status.HTTP_204_NO_CONTENT) # 3. GCBV class GCourseList(generics.ListCreateAPIView): # generics里有很多定义好的APIView queryset = Course.objects.all() serializer_class = CourseSerializer def perform_create(self, serializer): serializer.save(teacher=self.request.user) # from rest_framework import mixins # from rest_framework.generics import GenericAPIView # class GCourseDetail(mixins.RetrieveModelMixin, # mixins.UpdateModelMixin, # mixins.DestroyModelMixin, # GenericAPIView): class GCourseDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Course.objects.all() serializer_class = CourseSerializer # 4. ViewSets class CourseViewSet(viewsets.ModelViewSet): queryset = Course.objects.all() serializer_class = CourseSerializer def perform_create(self, serializer): serializer.save(teacher=self.request.user)

    routers 配置路由

    # course/urls.py from django.urls import path, include from rest_framework.routers import DefaultRouter from course import views router = DefaultRouter() router.register(prefix='viewsets', viewset=views.CourseViewSet) urlpatterns = [ # FBV path('fbv/list/', views.course_list, name='fbv-list'), path('fbv/detail/<int:pk>/', views.course_detail, name='fbv-detail'), # CBV path('cbv/list/', views.CourseList.as_view(), name='cbv-list'), path('cbv/detail/<int:pk>/', views.CourseDetail.as_view(), name='cbv-detail'), # GCBV path('gcbv/list/', views.GCourseList.as_view(), name='gcbv-list'), path('gcbv/detail/<int:pk>/', views.GCourseDetail.as_view(), name='gcbv-detail'), # ViewSets # path('viewsets/list/', views.CourseViewSet.as_view({ # "get": "list", "post": "create" # }), name='viewsets-list'), # path('viewsets/detail/<int:pk>/', views.CourseViewSet.as_view({ # "get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy" # }), name='viewsets-detail'), path('', include(router.urls)), ] # drf_tutorial/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api-auth/', include('rest_framework.urls')), path('course/', include('course.urls')), ]

Token 验证

  1. # 1. Django 使用django manage.py drf_create_token 用户 # 生成token # 2. Django 使用信号机制生成token # 1) INSTALLED_APPS = [ "rest_framework.authtoken" ] # 2) REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.TokenAuthentication", ] } # 3) 使用signals信号机制生成token from django.db.models.signals import post_save # 信号 from django.dispatch import receiver # receiver装饰 from django.contrib.auth.models import User # 或者是下 from django.conf import settings from rest_framework.authtoken.models import Token # token表导入 # @receiver(post_save, sender=User) @receiver(post_save, sender=settings.AUTH_USER_MODEL) # django的信号机制 def generate_token(sender, instance=None, created=False, **kwargs): """ 生成token :param sender: :param instance: :param created: :param kwargs: :return: """ if created: Token.objects.create(user=instance) # 4) drf_tutorial/urls.py 用来发送生成请求 from rest_framework.authtoken import views urlpatterns = [ path('api-token-auth/', views.obtain_auth_token), # 获取token的接口 ]

认证

  1. # 首先,默认的REST_FRAMEWORK全局配置中有控制验证信息 # 导包 from rest_framework.decorators import authentication_classes from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication # 实现定制化的验证类型 # 1. 方法 @authentication_classes((BasicAuthentication, SessionAuthentication, TokenAuthentication)) # 给方法加验证类型 # 2. 类 authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication) # 类视图添加内置authentication_classes

权限

  1. 加权限

    # 权限类型 # from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated, IsAdminUser, AllowAny # AllowAny是允许所有访问,无需登录验证 # 加权限 类似加认证 from rest_framework.decorators import permission_classes from rest_framework.permissions import IsAuthenticated # 实现定制化的权限 # 1. 方法 @permission_classes((IsAuthenticated, )) # 2. 类 permission_classes = (IsAuthenticated, )

    不同用户创建者之间不应该有更新数据的权限

    # course/permissions.py from rest_framework import permissions class IsOwnerReadonly(permissions.BasePermission): def has_object_permission(self, request, view, obj): """ 所有request都有读权限,因此一律允许GET/HEAD/OPTIONS :param request: :param view: :param obj: :return: """ # if request.method in ('GET', 'HEAD', 'OPTIONS'): if request.method in permissions.SAFE_METHODS: return True return obj.teacher == request.user # course/views.py # 将自定义的权限导入 from .permissions import IsOwnerReadonly # 添加更新权限到put方法 # 1. 方法 @permission_classes((IsAuthenticated, IsOwnerReadonly,)) # 2. 类 permission_classes = (IsAuthenticated, IsOwnerReadonly,)

生成API接口文档

  1. get_schema_view

    # drf_tutorial/settings.py REST_FRAMEWORK = { 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema', } # drf_tutorial/urls.py from rest_framework.schemas import get_schema_view schema_view = get_schema_view(title='DRF API 文档', description='xxx') url_patterns = [ path('schema/', schema_view), ] # 装个chrome的JsonView插件,可以查看相应的API文档
  2. include_docs_urls: ip:port/docs/ ==> 查看项目实现的接口

    # drf_tutorial/settings.py REST_FRAMEWORK = { 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', } # drf_tutorial/urls.py from rest_framework.documentation import include_docs_urls url_patterns = [ path('docs/', include_docs_urls(title='DRF API 文档', description='Django rest framework 快速入门')), ]

__EOF__

作  者bwxx
出  处https://www.cnblogs.com/bwlearn/p/18198926
关于博主:编程路上的小学生,热爱技术,喜欢专研。评论和私信会在第一时间回复。或者直接私信我。
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

posted @   一个慵懒的人  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
0
0
关注
跳至底部
点击右上角即可分享
微信分享提示