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 序列化
-
继承模型序列化 models.ModelSerializer
-
超链接模型序列化 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. 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. 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的接口 ]
认证
-
# 首先,默认的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
权限
-
加权限
# 权限类型 # 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接口文档
-
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文档
-
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
关于博主:编程路上的小学生,热爱技术,喜欢专研。评论和私信会在第一时间回复。或者直接私信我。
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?