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

目录

一、搭建项目开发环境

[1.1 pycharm创建项目](#1.1 pycharm创建项目)

[1.2 修改配置settings.py](#1.2 修改配置settings.py)

[1.3 新增 static与staticfiles文件夹](#1.3 新增 static与staticfiles文件夹)

[1.4 生成数据表](#1.4 生成数据表)

[1.5 创建超级用户](#1.5 创建超级用户)

[1.6 启动项目](#1.6 启动项目)

二、安装REST_Framework

[2.1 安装](#2.1 安装)

[2.2 配置settings](#2.2 配置settings)

[2.3 重新执行生成数据库脚本](#2.3 重新执行生成数据库脚本)

三、修改路由

四、studyApp应用开发

[4.1 修改apps.py](#4.1 修改apps.py)

[4.2 创建models.py](#4.2 创建models.py)

[4.3 修改admin.py](#4.3 修改admin.py)

[4.4 生成数据表](#4.4 生成数据表)

[4.5 添加库表数据](#4.5 添加库表数据)

[五、使用ModelSerializer序列化 模型类](#五、使用ModelSerializer序列化 模型类)

[5.1 创建serializers文件](#5.1 创建serializers文件)

[5.2 序列化models表中的Course](#5.2 序列化models表中的Course)

[5.3 带URL的HyperlinkedModelSerializer(非必须)](#5.3 带URL的HyperlinkedModelSerializer(非必须))

[六、DRF视图开发RESful API接口](#六、DRF视图开发RESful API接口)

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

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

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

[6.2 DRF函数式编程Function Based View](#6.2 DRF函数式编程Function Based View)

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

[6.2.2 添加路由](#6.2.2 添加路由)

[6.2.3 访问验证](#6.2.3 访问验证)

[6.2.4 测试新增](#6.2.4 测试新增)

[6.2.5 查询列表](#6.2.5 查询列表)

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

[6.2.7 添加路由](#6.2.7 添加路由)

[6.2.8 查询单个](#6.2.8 查询单个)

[6.2.9 修改单个](#6.2.9 修改单个)

[6.2.10 删除单个](#6.2.10 删除单个)

[6.3 DRF类视图Class Based View](#6.3 DRF类视图Class Based View)

[6.3.1 代码](#6.3.1 代码)

[6.3.2 更新url](#6.3.2 更新url)

[6.3.3 测试](#6.3.3 测试)

[6.4 通用类视图Generic Classed Based View](#6.4 通用类视图Generic Classed Based View)

[6.4.1 代码](#6.4.1 代码)

[6.3.2 添加路由](#6.3.2 添加路由)

[6.3.3 测试](#6.3.3 测试)

[6.5 DRF的视图集viewsets](#6.5 DRF的视图集viewsets)

[6.5.1 代码](#6.5.1 代码)

[6.5.2 路由urls---》 这个写法与之前路由不一样](#6.5.2 路由urls---》 这个写法与之前路由不一样)

[6.5.3 测试](#6.5.3 测试)

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

[7.1 BasicAuthenrication用户名密码认证](#7.1 BasicAuthenrication用户名密码认证)

[7.2 SessionAuthenrication认证](#7.2 SessionAuthenrication认证)

[7.3 TokenAuthenrication认证](#7.3 TokenAuthenrication认证)

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

[7.3.2 通过django的信号机制生成token](#7.3.2 通过django的信号机制生成token)

[7.3.2.1 在视图写函数实现](#7.3.2.1 在视图写函数实现)

[7.3.2.2 项目urls配置路由](#7.3.2.2 项目urls配置路由)

[7.3.2.3 后台创建一个用户](#7.3.2.3 后台创建一个用户)

[7.3.2.4 调用接口生成token](#7.3.2.4 调用接口生成token)

[7.3.2.5 其他接口使用token](#7.3.2.5 其他接口使用token)

[7.3.2.6 每个方法设置不同认证](#7.3.2.6 每个方法设置不同认证)

八、DRF的权限

[8.1 常用的权限类](#8.1 常用的权限类)

[8.2 设置权限策略](#8.2 设置权限策略)

[8.3 如何自定义对象级别权限](#8.3 如何自定义对象级别权限)

[8.3.1 新建permissons.py文件](#8.3.1 新建permissons.py文件)

[8.3.2 导入到视图views.py应用](#8.3.2 导入到视图views.py应用)

[8.3.3 测试](#8.3.3 测试)

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

[9.1 如何生成接口文档](#9.1 如何生成接口文档)

[9.1.1 安装库](#9.1.1 安装库)

[9.1.2 settings配置](#9.1.2 settings配置)

[9.1.3 urls配置](#9.1.3 urls配置)

[9.1.4 访问](#9.1.4 访问)

[9.2 接口文档的使用方法](#9.2 接口文档的使用方法)

[9.2.1 修改settings](#9.2.1 修改settings)

[9.2.2 修改urls](#9.2.2 修改urls)

[9.2.3 访问](#9.2.3 访问)

[9.2.4 使用](#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
bocai@163.com
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 使用

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

相关推荐
qq_174482857514 分钟前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦1 小时前
Scala的Array(2)
开发语言·后端·scala
2401_882727571 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
心仪悦悦2 小时前
Scala中的集合复习(1)
开发语言·后端·scala
代码小鑫2 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖2 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶2 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka
uzong3 小时前
一个 IDEA 老鸟的 DEBUG 私货之多线程调试
java·后端
飞升不如收破烂~4 小时前
Spring boot常用注解和作用
java·spring boot·后端