Bootstrap

【django】django RESTFramework前后端分离框架快速入门

目录

一、搭建项目开发环境

1.1 pycharm创建项目

1.2 修改配置settings.py 

1.3 新增 static与staticfiles文件夹

1.4 生成数据表

1.5 创建超级用户

1.6 启动项目

 二、安装REST_Framework

2.1 安装

2.2 配置settings

2.3 重新执行生成数据库脚本

三、修改路由

 四、studyApp应用开发

4.1 修改apps.py

 4.2 创建models.py

4.3 修改admin.py

4.4 生成数据表

4.5 添加库表数据

五、使用ModelSerializer序列化 模型类

5.1 创建serializers文件

5.2 序列化models表中的Course

5.3 带URL的HyperlinkedModelSerializer(非必须)

 六、DRF视图开发RESful API接口

6.1 使用django原生编写API接口(可跳过,不推荐)

6.1.1 django函数式编程Function Based View(不推荐)

6.1.2 django原生类视图Class Based View(不推荐)

6.2 DRF函数式编程Function Based View

6.2.1 编码代码-----》(查询列表+新增)

6.2.2 添加路由

 6.2.3 访问验证

6.2.4 测试新增

6.2.5 查询列表

 6.2.6 编写代码 ----》(修改、删除,查询单个)

6.2.7  添加路由

6.2.8 查询单个

6.2.9 修改单个

6.2.10 删除单个 

6.3 DRF类视图Class Based View

6.3.1 代码

 6.3.2 更新url

6.3.3 测试

6.4 通用类视图Generic Classed Based View

6.4.1 代码

6.3.2 添加路由

6.3.3 测试

6.5 DRF的视图集viewsets

6.5.1 代码

6.5.2 路由urls---》 这个写法与之前路由不一样

6.5.3 测试

 七、DRF的认证(了解即可)

7.1 BasicAuthenrication用户名密码认证

7.2 SessionAuthenrication认证

7.3 TokenAuthenrication认证

7.3.1 使用django manage.py 生成token(测试使用)

7.3.2 通过django的信号机制生成token

7.3.2.1 在视图写函数实现

7.3.2.2 项目urls配置路由

7.3.2.3 后台创建一个用户

 7.3.2.4 调用接口生成token

 7.3.2.5 其他接口使用token

 7.3.2.6 每个方法设置不同认证

八、DRF的权限

8.1 常用的权限类

8.2 设置权限策略

8.3 如何自定义对象级别权限

8.3.1 新建permissons.py文件

8.3.2 导入到视图views.py应用

8.3.3 测试

九、如何使用drf的接口文档 

9.1 如何生成接口文档

9.1.1 安装库

9.1.2 settings配置

 9.1.3 urls配置

9.1.4 访问

9.2 接口文档的使用方法

9.2.1 修改settings

9.2.2 修改urls

 9.2.3 访问

9.2.4 使用


前言:django RESTFramework基础学习整理

一、搭建项目开发环境

1.1 pycharm创建项目

1.2 修改配置settings.py 

ALLOWED_HOSTS = ['*']

.
.
.

# LANGUAGE_CODE = 'en-us'
# TIME_ZONE = 'UTC'
# USE_TZ = True
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False
USE_I18N = True
.
.
.
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'staticfiles')]

1.3 新增 static与staticfiles文件夹

1.4 生成数据表

这里使用默认的数据库 

python manage.py makemigrations

python manage.py migrate


1.5 创建超级用户

# 创建超级用户
python manage.py createsuperuser

1、输入邮箱,随便
2、输入密码
3、再次数据密码 
4、 如果密码太简单会提示, 忽略就点Y

1.6 启动项目

python manage.py runserver

http://127.0.0.1:8000/admin/
输入刚才设置的用户  root  123456,能登录成功就说明用户创建成功

 二、安装REST_Framework

2.1 安装


pip install djangorestframework

pip install coreapi # 第九章使用

pip install pyyaml   # 第九章使用

2.2 配置settings

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'studyApp.apps.StudyappConfig',
    'rest_framework', #rest-framework API
    'rest_framework.authtoken' # DRF 自带的token认证
]
.
.
.


#DRF的全局配置
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
    'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',
    'DEFAULT_RENDER_CLASSES': [# 渲染response ,可以不写
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renders.BrowsableAPIRender',
    ],
    'DEFAULT_PARSER_CLASSES': [  # 解析request.data
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],
    'DEFAULT_PERMISSION_CLASSES': [  # 权限
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ],
    'DERAULT_AUTHENTICATION_CLASSES': [  # 认证
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ]
}

2.3 重新执行生成数据库脚本

python manage.py makemigrations

python manage.py migrate

三、修改路由


from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('studyApp/',include('studyApp.urls')),
    path('api-auth/', include('rest_framework.urls')), # DRF登录退出接口,可点击进去看看
]
登录
http://127.0.0.1:8000/api-auth/login/

 四、studyApp应用开发

4.1 修改apps.py

from django.apps import AppConfig


class StudyappConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'studyApp'
    verbose_name = '学习APP'

 4.2 创建models.py

from django.db import models
from django.conf import settings



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, help_text='创建时间', verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')

    class Meta:
        verbose_name = '课程信息',
        verbose_name_plural = verbose_name
        ordering = ['price',]
    def __str__(self):
        return self.name

4.3 修改admin.py

将model.py创建的Course字段添加到后台系统,方面后期添加数据

from django.contrib import admin
from .models import Course

# Register your models here.
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ('name', 'introduction','teacher','price')
    serch_fields = list_display
    list_filter = list_display

4.4 生成数据表

python manage.py makemigrations

python manage.py migrate


4.5 添加库表数据

http://127.0.0.1:8000/admin

五、使用ModelSerializer序列化 模型类

5.1 创建serializers文件

5.2 序列化models表中的Course

注意:teacher是外键,复用了django的用户表,外键序列化还可以使用遍历深度

在Meta当中设置depth=1 , 数字越大,深度越大,

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 9:30
# @Author  : super
# @File    : serializers.py
# @Software: PyCharm
# @Describe:
from rest_framework import serializers
from .models import Course
from django.contrib.auth.models import User  # 导入用户模型


"""
    用户序列化器
"""
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'


class CourseSerializer(serializers.ModelSerializer):
    teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键显示名称
    
    class Meta:
        model = Course
        fields = '__all__'
        # fields = ('id', 'name', 'teacher', 'price', 'introduction', 'created_at', 'updated_at')

5.3 带URL的HyperlinkedModelSerializer(非必须)

这里是讲解,后面例子没有使用到,可注解掉

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 9:30
# @Author  : super
# @File    : serializers.py
# @Software: PyCharm
# @Describe:
from rest_framework import serializers
from .models import Course
from django.contrib.auth.models import User  # 导入用户模型


"""
    用户序列化器
"""
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'



class CourseSerializer(serializers.HyperlinkedModelSerializer):
    teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键显示名称

    class Meta:
        model = Course       
        # url 是默认值,可在settings.py设置URL_FIELD_NAME使全局生效
        fields = ('id', 'url', 'teacher', 'price', 'introduction', 'created_at', 'updated_at')

如果要更url,这样设置,(不建议)

 六、DRF视图开发RESful API接口

6.1 使用django原生编写API接口(可跳过,不推荐)

6.1.1 django函数式编程Function Based View(不推荐)

使用django原生的函数式编写api接口

from django.shortcuts import render
import json
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt   # 用于免除csrf验证
# Create your views here.
coures_dict = {  
    "name": "python",  
    "introduction": "python基础入门",  
    "price": 100  
}


@csrf_exempt
def course_list(request):
    '''
    django原生的fbv式编写API接口
    :param request:
    :return:
    '''
    if request.method == 'Get':
        return JsonResponse(coures_dict)
        # return HttpResponse(json.dumps(coures_dict), content_type='application/json')  # 这个与上面JsonResponse作用一样
    
    if request.method == 'POST':
        course_data = json.loads(request.body.decode('utf-8'))
        # return JsonResponse(course_data, safe=False) # 这个与下面的JsonResponse作用一样
        return HttpResponse(json.dumps(course_data), content_type='application/json')

6.1.2 django原生类视图Class Based View(不推荐)

使用django原生的类编写api接口

import json
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt   # 用于免除csrf验证
from django.utils.decorators import method_decorator  # 用于方法免除csrf验证
from django.views import View

@method_decorator(csrf_exempt, name='dispatch')
class CourseView(View):
    '''
    django原生的cbv式编写API接口
    '''
    def get(self, request):
        return JsonResponse(coures_dict)

    def post(self, request):
        course_data = json.loads(request.body.decode('utf-8'))
        return JsonResponse(course_data, safe=False)

6.2 DRF函数式编程Function Based View

6.2.1 编码代码-----》(查询列表+新增)

from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer


"""
 一、 函数式编程 FBV
"""
@api_view(['GET', 'POST'])
def coures_list(request):
    '''
    获取课程列表或新增一个课程
    :param request:
    :return:
    '''
    if request.method == 'GET':
        courses = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=courses.data,status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = CourseSerializer(data=request.data) # partial=True 只验证部分字段,适用于非必填字段
        if serializer.is_valid():
            serializer.save(teacher=request.user) # teacher 字段为外键,获取登录用户id,因为复用了django的用户模型,有认证功能
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

6.2.2 添加路由

在应用新增urls文件,输入内容

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 10:27
# @Author  : super
# @File    : urls.py
# @Software: PyCharm
# @Describe:
from django.urls import path,include
from studyApp import views

urlpatterns = [
 path('fbv/list/', views.coures_list, name='fbv-list'), # 函数视图FBV

]

 6.2.3 访问验证

http://127.0.0.1:8000/studyApp/fbv/list/

因为这里设置了全局的身份认证,需要登录

6.2.4 测试新增

json

{
	"name": "python",
	"introduction": "python基础入门",
	"price": 100
}

6.2.5 查询列表

 

 6.2.6 编写代码 ----》(修改、删除,查询单个)

from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer


"""
 一、 函数式编程 FBV
"""
@api_view(['GET', 'POST'])
def coures_list(request):
    '''
    获取课程列表或新增一个课程
    :param request:
    :return:
    '''
    if request.method == 'GET':
        courses = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=courses.data,status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = CourseSerializer(data=request.data) # partial=True 只验证部分字段,适用于非必填字段
        if serializer.is_valid():
            serializer.save(teacher=request.user) # teacher 字段为外键,获取登录用户id,因为复用了django的用户模型,有认证功能
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=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)
    except Course.DoesNotExist:
        return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        serializer = CourseSerializer(course)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'PUT':
        serializer = CourseSerializer(instance=course, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    elif request.method == 'DELETE':
        course.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    else:
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

6.2.7  添加路由

from django.urls import path,include
from studyApp import views

urlpatterns = [
 path('fbv/list/', views.coures_list, name='fbv-list'), # 函数视图FBV
 path('fbv/detail/<int:pk>/', views.course_detail, name='fbv-detail'),

]

6.2.8 查询单个

http://127.0.0.1:8000/studyApp/fbv/detail/2/

6.2.9 修改单个

请求体

{
	"name": "菠菜的野蛮生长",
	"introduction": "编码人生",
	"price": 100
}

 

6.2.10 删除单个 

知识点:使用postman测试的话注意这个地方

另外一种设置方式:

 继承

  

6.3 DRF类视图Class Based View

6.3.1 代码

from django.shortcuts import render
from rest_framework.decorators import api_view  # fbv
from rest_framework.views import APIView  #cbv
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer


"""
 一、 函数式编程 FBV
"""
@api_view(['GET', 'POST'])
def coures_list(request):
    '''
    获取课程列表或新增一个课程
    :param request:
    :return:
    '''
    if request.method == 'GET':
        courses = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=courses.data,status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = CourseSerializer(data=request.data) # partial=True 只验证部分字段,适用于非必填字段
        if serializer.is_valid():
            serializer.save(teacher=request.user) # teacher 字段为外键,获取登录用户id,因为复用了django的用户模型,有认证功能
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=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)
    except Course.DoesNotExist:
        return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        serializer = CourseSerializer(course)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'PUT':
        serializer = CourseSerializer(instance=course, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    elif request.method == 'DELETE':
        course.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    else:
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

"""
 二、 函数式编程 CBV
"""
class CourseList(APIView):
    """
    获取课程列表或新增一个课程
    """
    def get(self, request):
        queryset = Course.objects.all()
        serializer = CourseSerializer(instance=queryset, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        serializer = CourseSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(teacher=self.request.user)
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CourseDetail(APIView):
    """
    获取单个课程详情,更新或删除一个课程
    """

    @staticmethod
    def get_object(pk):
        '''
        获取课程对象
        :param self:
        :param pk:
        :return:
        '''
        try:
            return Course.objects.get(pk=pk)
        except Course.DoesNotExist:
            return


    def get(self, request, pk):
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(obj)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    def put(self, request, pk):
        '''
        更新课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(instance=obj, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    def delete(self, request, pk):
        '''
        删除课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

 6.3.2 更新url

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 10:27
# @Author  : super
# @File    : urls.py
# @Software: PyCharm
# @Describe:
from django.urls import path,include
from studyApp import views

urlpatterns = [
 path('fbv/list/', views.coures_list, name='fbv-list'), # 函数视图FBV
 path('fbv/detail/<int:pk>/', views.course_detail, name='fbv-detail'), # 函数视图FBV
 path('cbv/list/', views.CourseList.as_view(), name='cbv-list'), # 类视图CBV
 path('cbv/detail/<int:pk>/', views.CourseDetail.as_view(), name='cbv-detail'), # 类视图CBV

]

6.3.3 测试

查询全部

新增 

修改

删除

6.4 通用类视图Generic Classed Based View

6.4.1 代码

如果没有那个teacher ,那个方法重写可以不需要

from django.shortcuts import render
from rest_framework.decorators import api_view  # fbv
from rest_framework.views import APIView  #cbv
from rest_framework import generics # gcb通用视图类
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer


"""
 一、 函数式编程 FBV
"""
@api_view(['GET', 'POST'])
def coures_list(request):
    '''
    获取课程列表或新增一个课程
    :param request:
    :return:
    '''
    if request.method == 'GET':
        courses = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=courses.data,status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = CourseSerializer(data=request.data) # partial=True 只验证部分字段,适用于非必填字段
        if serializer.is_valid():
            serializer.save(teacher=request.user) # teacher 字段为外键,获取登录用户id,因为复用了django的用户模型,有认证功能
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=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)
    except Course.DoesNotExist:
        return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        serializer = CourseSerializer(course)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'PUT':
        serializer = CourseSerializer(instance=course, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    elif request.method == 'DELETE':
        course.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    else:
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

"""
 二、 函数式编程 CBV
"""
class CourseList(APIView):
    """
    获取课程列表或新增一个课程
    """
    def get(self, request):
        queryset = Course.objects.all()
        serializer = CourseSerializer(instance=queryset, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        serializer = CourseSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(teacher=self.request.user)
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CourseDetail(APIView):
    """
    获取单个课程详情,更新或删除一个课程
    """

    @staticmethod
    def get_object(pk):
        '''
        获取课程对象
        :param self:
        :param pk:
        :return:
        '''
        try:
            return Course.objects.get(pk=pk)
        except Course.DoesNotExist:
            return


    def get(self, request, pk):
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(obj)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    def put(self, request, pk):
        '''
        更新课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(instance=obj, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    def delete(self, request, pk):
        '''
        删除课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


'''
 三、 通用视图类
'''

class CourseGenericAPIView(generics.ListCreateAPIView):
    '''
    获取课程列表或新增一个课程
    '''
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    def perform_create(self, serializer):   # 重写perform_create方法,在保存之前添加teacher字段
        serializer.save(teacher=self.request.user)
        

class CourseGenericDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    '''
    获取单个课程详情,更新或删除一个课程
    '''
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

6.3.2 添加路由

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 10:27
# @Author  : super
# @File    : urls.py
# @Software: PyCharm
# @Describe:
from django.urls import path,include
from studyApp import views

urlpatterns = [
 path('fbv/list/', views.coures_list, name='fbv-list'), # 函数视图FBV
 path('fbv/detail/<int:pk>/', views.course_detail, name='fbv-detail'), # 函数视图FBV
 path('cbv/list/', views.CourseList.as_view(), name='cbv-list'), # 类视图CBV
 path('cbv/detail/<int:pk>/', views.CourseDetail.as_view(), name='cbv-detail'), # 类视图CBV
 path('gcbv/list/', views.CourseGenericAPIView.as_view(),name='gcbv-list'), # 通用视图类gcbv
 path('gcbv/detail/<int:pk>/', views.CourseGenericDetailAPIView.as_view(), name='gcbv-detail'),# 通用视图类gcbv


]

6.3.3 测试

查询列表

新增

查询单个

修改

删除

6.5 DRF的视图集viewsets

6.5.1 代码

from django.shortcuts import render
from rest_framework.decorators import api_view  # fbv
from rest_framework.views import APIView  #cbv
from rest_framework import generics # gcbv通用视图类
from rest_framework import viewsets # 视图集
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer


"""
 一、 函数式编程 FBV
"""
@api_view(['GET', 'POST'])
def coures_list(request):
    '''
    获取课程列表或新增一个课程
    :param request:
    :return:
    '''
    if request.method == 'GET':
        courses = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=courses.data,status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = CourseSerializer(data=request.data) # partial=True 只验证部分字段,适用于非必填字段
        if serializer.is_valid():
            serializer.save(teacher=request.user) # teacher 字段为外键,获取登录用户id,因为复用了django的用户模型,有认证功能
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=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)
    except Course.DoesNotExist:
        return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        serializer = CourseSerializer(course)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'PUT':
        serializer = CourseSerializer(instance=course, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    elif request.method == 'DELETE':
        course.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    else:
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

"""
 二、 函数式编程 CBV
"""
class CourseList(APIView):
    """
    获取课程列表或新增一个课程
    """
    def get(self, request):
        queryset = Course.objects.all()
        serializer = CourseSerializer(instance=queryset, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        serializer = CourseSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(teacher=self.request.user)
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CourseDetail(APIView):
    """
    获取单个课程详情,更新或删除一个课程
    """

    @staticmethod
    def get_object(pk):
        '''
        获取课程对象
        :param self:
        :param pk:
        :return:
        '''
        try:
            return Course.objects.get(pk=pk)
        except Course.DoesNotExist:
            return


    def get(self, request, pk):
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(obj)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    def put(self, request, pk):
        '''
        更新课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(instance=obj, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    def delete(self, request, pk):
        '''
        删除课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


'''
 三、 通用视图类
'''

class CourseGenericAPIView(generics.ListCreateAPIView):
    '''
    获取课程列表或新增一个课程
    '''
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    def perform_create(self, serializer):   # 重写perform_create方法,在保存之前添加teacher字段
        serializer.save(teacher=self.request.user)


class CourseGenericDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    '''
    获取单个课程详情,更新或删除一个课程
    '''
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

'''
 四、 视图集
'''
class CourseViewSet(viewsets.ModelViewSet):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    def perform_create(self, serializer):  # 重写perform_create方法,在保存之前添加teacher字段
        serializer.save(teacher=self.request.user)

6.5.2 路由urls---》 这个写法与之前路由不一样

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 10:27
# @Author  : super
# @File    : urls.py
# @Software: PyCharm
# @Describe:
from django.urls import path,include
from studyApp import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(prefix='courseviewsets', viewset=views.CourseViewSet)

urlpatterns = [
 # 函数视图FBV
 path('fbv/list/', views.coures_list, name='fbv-list'), # 函数视图FBV
 path('fbv/detail/<int:pk>/', views.course_detail, name='fbv-detail'), # 函数视图FBV
 # 类视图CBV
 path('cbv/list/', views.CourseList.as_view(), name='cbv-list'), # 类视图CBV
 path('cbv/detail/<int:pk>/', views.CourseDetail.as_view(), name='cbv-detail'), # 类视图CBV
 # 通用视图类gcbv
 path('gcbv/list/', views.CourseGenericAPIView.as_view(),name='gcbv-list'), # 通用视图类gcbv
 path('gcbv/detail/<int:pk>/', views.CourseGenericDetailAPIView.as_view(), name='gcbv-detail'),# 通用视图类gcbv
 # 视图集写法不一样
 path('', include(router.urls)),
]

6.5.3 测试

列表

新增

查询单个

 

修改单个

删除单个 

 七、DRF的认证(了解即可)

前面配置的三种认证,这里了解即可,一般使用jwt,博主其他博文有介绍

7.1 BasicAuthenrication用户名密码认证

这个认证一般用于测试,不要在生产环境使用

7.2 SessionAuthenrication认证

使用的是django默认的后端会话, 

7.3 TokenAuthenrication认证

这个要配置,之前配置了

 之前执行数据同步将对应库表更新到了数据库,双击这个默认数据库

7.3.1 使用django manage.py 生成token(测试使用)

python manage.py drf_create_token root  
# root  是对应用户

在上面的库表可见

7.3.2 通过django的信号机制生成token

7.3.2.1 在视图写函数实现
'''
token 认证
'''
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from rest_framework.authtoken.models import Token


@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)

7.3.2.2 项目urls配置路由

"""
URL configuration for djangoRESTFramework project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include
from rest_framework.authtoken import views 

urlpatterns = [
    path('api-token-auth/', views.obtain_auth_token), # token认证
    path('admin/', admin.site.urls),
    path('studyApp/',include('studyApp.urls')),
    path('api-auth/', include('rest_framework.urls')), # DRF登录退出接口,可点击进去看看
]
7.3.2.3 后台创建一个用户
bocai
[email protected]

 7.3.2.4 调用接口生成token

 7.3.2.5 其他接口使用token

 7.3.2.6 每个方法设置不同认证

 方法认证优先级大于全局settings

函数视图添加方法

类视图\通用类、视图集添加方法相同

from django.shortcuts import render
from rest_framework.decorators import api_view, authentication_classes # fbv
from rest_framework.views import APIView  #cbv
from rest_framework import generics # gcbv通用视图类
from rest_framework import viewsets # 视图集
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer
from rest_framework.authentication import BasicAuthentication,SessionAuthentication,TokenAuthentication

'''
token 认证
'''
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from rest_framework.authtoken.models import Token


@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)


"""
 一、 函数式编程 FBV
"""
@api_view(['GET', 'POST'])
@authentication_classes((BasicAuthentication,TokenAuthentication))
def coures_list(request):
    '''
    获取课程列表或新增一个课程
    :param request:
    :return:
    '''
    if request.method == 'GET':
        courses = CourseSerializer(instance=Course.objects.all(), many=True)
        return Response(data=courses.data,status=status.HTTP_200_OK)
    elif request.method == 'POST':
        serializer = CourseSerializer(data=request.data) # partial=True 只验证部分字段,适用于非必填字段
        if serializer.is_valid():
            serializer.save(teacher=request.user) # teacher 字段为外键,获取登录用户id,因为复用了django的用户模型,有认证功能
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', 'PUT', 'DELETE'])
@authentication_classes((BasicAuthentication,TokenAuthentication))
def course_detail(request, pk):
    '''
    获取单个课程详情,更新或删除一个课程
    :param request:
    :param pk:
    :return:
    '''''
    try:
        course = Course.objects.get(pk=pk)
    except Course.DoesNotExist:
        return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        serializer = CourseSerializer(course)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    elif request.method == 'PUT':
        serializer = CourseSerializer(instance=course, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    elif request.method == 'DELETE':
        course.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    else:
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

"""
 二、 函数式编程 CBV
"""
class CourseList(APIView):
    """
    获取课程列表或新增一个课程
    """
    authentication_classes = (BasicAuthentication,SessionAuthentication,TokenAuthentication)
    def get(self, request):
        queryset = Course.objects.all()
        serializer = CourseSerializer(instance=queryset, many=True)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        serializer = CourseSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(teacher=self.request.user)
            return Response(data=serializer.data, status=status.HTTP_201_CREATED)
        return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CourseDetail(APIView):
    """
    获取单个课程详情,更新或删除一个课程
    """
    authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)
    @staticmethod
    def get_object(pk):
        '''
        获取课程对象
        :param self:
        :param pk:
        :return:
        '''
        try:
            return Course.objects.get(pk=pk)
        except Course.DoesNotExist:
            return


    def get(self, request, pk):
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(obj)
        return Response(data=serializer.data, status=status.HTTP_200_OK)
    def put(self, request, pk):
        '''
        更新课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        serializer = CourseSerializer(instance=obj, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    def delete(self, request, pk):
        '''
        删除课程
        :param request:
        :param pk:
        :return:
        '''
        obj = self.get_object(pk=pk)
        if obj is None:
            return Response({'message': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
        obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


'''
 三、 通用视图类
'''

class CourseGenericAPIView(generics.ListCreateAPIView):
    '''
    获取课程列表或新增一个课程
    '''
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

    def perform_create(self, serializer):   # 重写perform_create方法,在保存之前添加teacher字段
        serializer.save(teacher=self.request.user)


class CourseGenericDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    '''
    获取单个课程详情,更新或删除一个课程
    '''
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

'''
 四、 视图集
'''
class CourseViewSet(viewsets.ModelViewSet):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    def perform_create(self, serializer):  # 重写perform_create方法,在保存之前添加teacher字段
        serializer.save(teacher=self.request.user)

八、DRF的权限

8.1 常用的权限类

8.2 设置权限策略

函数视图添加方法

类视图\通用类、视图集添加方法相同 

8.3 如何自定义对象级别权限

8.3.1 新建permissons.py文件

# -*- coding: utf-8 -*-
# @Time    : 2024/11/1 15:58
# @Author  : super
# @File    : permissions.py
# @Software: PyCharm
# @Describe:
from rest_framework import permissions

class IsOwnerReadOnly(permissions.BasePermission):
    """
    自定义权限只允许对象的所有者编辑它。
    """
    def has_object_permission(self, request, view, obj):
        """
        判断用户是否有权限访问该对象。
        :param request:
        :param view:
        :param obj:
        :return: bool
        """
        if request.method in permissions.SAFE_METHODS:
            return True
        # 判断当前用户是否是该对象的拥有者
        return obj.teacher == request.user

8.3.2 导入到视图views.py应用

这里是修改

8.3.3 测试

这个id=9 是root创建的

 那么bocai无法修改

九、如何使用drf的接口文档 

9.1 如何生成接口文档

9.1.1 安装库

前面安装就可不安装

pip install coreapi
pip install pyyaml

9.1.2 settings配置

'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',

 9.1.3 urls配置

"""
URL configuration for djangoRESTFramework project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include
from rest_framework.authtoken import views
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(title='DRF API文档',description="API", version="0.1")

urlpatterns = [
    path('api-token-auth/', views.obtain_auth_token), # token认证
    path('admin/', admin.site.urls),
    path('studyApp/',include('studyApp.urls')),
    path('api-auth/', include('rest_framework.urls')), # DRF登录退出接口,可点击进去看看
    path('schema/', schema_view),
]

9.1.4 访问

http://127.0.0.1:8000/schema/

谷歌浏览器

9.2 接口文档的使用方法

9.2.1 修改settings

'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',

9.2.2 修改urls

"""
URL configuration for djangoRESTFramework project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include
from rest_framework.authtoken import views
from rest_framework.documentation import include_docs_urls
# from rest_framework.schemas import get_schema_view
# schema_view = get_schema_view(title='DRF API文档',description="API", version="0.1")

urlpatterns = [
    path('api-token-auth/', views.obtain_auth_token), # token认证
    path('admin/', admin.site.urls),
    path('studyApp/',include('studyApp.urls')),
    path('api-auth/', include('rest_framework.urls')), # DRF登录退出接口,可点击进去看看
    # path('schema/', schema_view),
    path('docs/',include_docs_urls(title='DRF API 文档',description='Django REST Framwork 快速入门')),
]

 9.2.3 访问

http://127.0.0.1:8000/docs/

9.2.4 使用

注意:配置认证页面不能刷新

;