Django REST Framework视图

Django REST Framework (DRF) 视图类详解

DRF 提供了丰富的视图类来构建 API,从基础到高级,满足不同复杂度的需求。以下是 DRF 的主要视图类及其使用场景:

1. 基础视图类

APIView

所有 DRF 视图的基类,相当于 Django 的 View 类的增强版。

复制代码
from rest_framework.views import APIView
from rest_framework.response import Response

class ArticleAPIView(APIView):
    def get(self, request):
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)
    
    def post(self, request):
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

特点:

  • 提供了 Django View 的所有功能

  • 增加了 DRF 的请求/响应处理

  • 内置了认证、权限、限流等机制

2. 通用视图类 (Generic Views)

GenericAPIView

扩展了 APIView,增加了常见的列表和详情视图行为。

复制代码
from rest_framework.generics import GenericAPIView

class ArticleList(GenericAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    def get(self, request):
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

具体通用视图

DRF 提供了5个具体的通用视图类:

  1. ListAPIView - 只读列表

    复制代码
    from rest_framework.generics import ListAPIView
    
    class ArticleList(ListAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  2. RetrieveAPIView - 只读单个实例

    复制代码
    from rest_framework.generics import RetrieveAPIView
    
    class ArticleDetail(RetrieveAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  3. CreateAPIView - 只创建

    复制代码
    from rest_framework.generics import CreateAPIView
    
    class ArticleCreate(CreateAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  4. UpdateAPIView - 只更新

    复制代码
    from rest_framework.generics import UpdateAPIView
    
    class ArticleUpdate(UpdateAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  5. DestroyAPIView - 只删除

    复制代码
    from rest_framework.generics import DestroyAPIView
    
    class ArticleDelete(DestroyAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer

组合通用视图

  1. ListCreateAPIView - 列表 + 创建

    复制代码
    from rest_framework.generics import ListCreateAPIView
    
    class ArticleListCreate(ListCreateAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  2. RetrieveUpdateAPIView - 详情 + 更新

    复制代码
    from rest_framework.generics import RetrieveUpdateAPIView
    
    class ArticleRetrieveUpdate(RetrieveUpdateAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  3. RetrieveDestroyAPIView - 详情 + 删除

    复制代码
    from rest_framework.generics import RetrieveDestroyAPIView
    
    class ArticleRetrieveDestroy(RetrieveDestroyAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer
  4. RetrieveUpdateDestroyAPIView - 详情 + 更新 + 删除

    复制代码
    from rest_framework.generics import RetrieveUpdateDestroyAPIView
    
    class ArticleRUD(RetrieveUpdateDestroyAPIView):
        queryset = Article.objects.all()
        serializer_class = ArticleSerializer

3. 视图集 (ViewSets)

ViewSet

将多个视图逻辑组合到一个类中。

复制代码
from rest_framework.viewsets import ViewSet

class ArticleViewSet(ViewSet):
    def list(self, request):
        queryset = Article.objects.all()
        serializer = ArticleSerializer(queryset, many=True)
        return Response(serializer.data)
    
    def retrieve(self, request, pk=None):
        article = get_object_or_404(Article, pk=pk)
        serializer = ArticleSerializer(article)
        return Response(serializer.data)

GenericViewSet

结合了 GenericAPIView 和 ViewSet 的行为。

复制代码
from rest_framework.viewsets import GenericViewSet

class ArticleViewSet(GenericViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    def list(self, request):
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

ModelViewSet

提供完整的 CRUD 操作。

复制代码
from rest_framework.viewsets import ModelViewSet

class ArticleViewSet(ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    # 自动获得 list, create, retrieve, update, destroy 方法

ReadOnlyModelViewSet

只提供只读操作。

复制代码
from rest_framework.viewsets import ReadOnlyModelViewSet

class ArticleViewSet(ReadOnlyModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    # 自动获得 list 和 retrieve 方法

4. 自定义动作

可以在 ViewSet 中添加自定义路由和方法:

复制代码
from rest_framework.decorators import action
from rest_framework.response import Response

class ArticleViewSet(ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    @action(detail=True, methods=['post'])
    def publish(self, request, pk=None):
        article = self.get_object()
        article.published = True
        article.save()
        return Response({'status': 'published'})
    
    @action(detail=False)
    def recent(self, request):
        recent_articles = Article.objects.order_by('-created_at')[:5]
        serializer = self.get_serializer(recent_articles, many=True)
        return Response(serializer.data)

5. 其他特殊视图

mixins

可以组合使用的混合类:

  1. ListModelMixin - 提供列表功能

  2. CreateModelMixin - 提供创建功能

  3. RetrieveModelMixin - 提供详情功能

  4. UpdateModelMixin - 提供更新功能

  5. DestroyModelMixin - 提供删除功能

    from rest_framework import mixins
    from rest_framework.viewsets import GenericViewSet

    class ArticleViewSet(mixins.ListModelMixin,
    mixins.CreateModelMixin,
    GenericViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

视图选择指南

  1. 简单API:使用 APIView 或 GenericAPIView

  2. 标准CRUD:使用通用视图 (ListCreateAPIView 等) 或 ModelViewSet

  3. 只读API:使用 ReadOnlyModelViewSet

  4. 需要自定义行为:使用 ViewSet 或 GenericViewSet 配合 mixins

  5. 复杂逻辑:从 APIView 继承并自行实现

路由配置示例

复制代码
# 对于 ViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'articles', ArticleViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

# 对于通用视图
urlpatterns = [
    path('articles/', ArticleList.as_view()),
    path('articles/<int:pk>/', ArticleDetail.as_view()),
]

DRF 的视图系统非常灵活,可以根据项目需求选择合适的视图类,从简单到复杂都能很好地支持。

应用示例

创建一个django项目

复制代码
创建 Django 项目
django-admin startproject test_rest

cd test_rest
创建应用
python manage.py startapp myapp

下载

复制代码
pip install djangorestframework

django项目注释掉一些不需要的,然后注册rest_framework

注释INSTALLED_APPS,MIDDLEWARE,TEMPLATES里自带的一些内容

复制代码
#settings.py

"""
Django settings for test_rest project.

Generated by 'django-admin startproject' using Django 5.2.5.

For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-!07)9y63bmcjs7__+me1a^sirkne20g1lz37bqrt&rt#%(5g1h'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    # 'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    # 'django.contrib.sessions',
    # 'django.contrib.messages',
    'django.contrib.staticfiles',
    "rest_framework"
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    #'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    # 'django.contrib.auth.middleware.AuthenticationMiddleware',
    # 'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'test_rest.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                # 'django.contrib.auth.context_processors.auth',
                # 'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'test_rest.wsgi.application'


# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

Django REST Framework (DRF) 中的 FBV 与 CBV

FBV(Function-Based Views,函数基础视图)和 CBV(Class-Based Views,类基础视图)是 Django 和 Django REST Framework (DRF) 中实现视图逻辑的两种主要方式。

复制代码
test_rest/urls.py

"""
URL configuration for test_rest project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/5.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.urls import path,include
from myapp import views
    
    


urlpatterns = [
    path('auth/',views.auth), #FBV
    path('myview/',views.MyView.as_view()),#CBV
    path('info/',views.MyView.as_view()),#CBV

]
复制代码
/myapp/views.py
复制代码
from django.http import JsonResponse
from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response


def auth(request):
    if request.method == "GET":
        return JsonResponse({"status":True,'message':'success',"method":request.method})
    elif request.method == "POST":
        return JsonResponse({"status":True,'message':'success',"method":request.method})
    return JsonResponse({"status":False,"method":request.method})


class MyView(View):
    def get(self,request):
        return JsonResponse({"status":True,'message':'success',"method":request.method})

    def post(self,request):
        return JsonResponse({"status":True,'message':'success',"method":request.method})

    def put(self,request):
        return JsonResponse({"status":True,'message':'success',"method":request.method})

    def delete(self,request):
        return JsonResponse({"status":True,'message':'success',"method":request.method})

class InfoView(APIView):
    def get(self,request):
        return Response({"status":True,'message':'success',"method":request.method})

Django REST Framework (DRF) 视图类详解

DRF 提供了丰富的视图类来构建 API,从基础到高级,满足不同复杂度的需求。以下是 DRF 的主要视图类及其使用场景:

开始前咱们先创建一个数据库,模型类,然后迁移数据

一、MySQL 数据库配置

1. 安装 MySQL 驱动
复制代码
pip install mysqlclient  # 推荐
# 或
pip install pymysql
2. 创建 MySQL 数据库
复制代码
CREATE DATABASE backstage CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
3. 配置 Django 的 settings.py
复制代码
# settings.py
DATABASES = {
    'default': {  # 默认数据库配置(Django 支持多数据库配置)
        'ENGINE': 'django.db.backends.mysql',  # 指定使用 MySQL 后端
        'NAME': 'backstage',                   # 数据库名(需提前创建)
        'USER': 'your_username',               # MySQL 用户名
        'PASSWORD': 'your_password',           # MySQL 密码
        'HOST': 'localhost',                   # 数据库服务器地址(默认本地)
        'PORT': '3306',                        # MySQL 默认端口
        'OPTIONS': {                           # 额外选项(关键配置)
            'charset': 'utf8mb4',              # 字符集设置为 utf8mb4
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",  # 初始化 SQL 命令
        }
    }
}

二、创建商品模型

定义模型(myapp/models.py)
复制代码
from django.db import models
from django.core.validators import MinValueValidator


class SpecificationCategory(models.Model):
    """规格类目表"""
    id = models.AutoField(primary_key=True, verbose_name="商品ID")
    name = models.CharField(max_length=50, verbose_name="规格类目名称")
    cid = models.CharField(max_length=50, verbose_name="类目编号")

    class Meta:
        db_table = 'spec_category'
        verbose_name = '商品规格类目'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Product(models.Model):
    """商品表"""
    id = models.AutoField(primary_key=True, verbose_name="商品ID")
    price = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name="商品价格"
    )
    stock = models.PositiveIntegerField(default=0, verbose_name="商品库存")

    # 一对多关联规格类目
    spec_category = models.ForeignKey(
        SpecificationCategory,
        on_delete=models.PROTECT,
        related_name='products',  # 注意改为复数形式
        verbose_name="规格类目"
    )
    image = models.CharField(
        max_length=500,
        blank=True,
        null=True,
        verbose_name="商品主图URL"
    )
    selling_points = models.CharField(
        max_length=200,
        blank=True,
        verbose_name="商品卖点"
    )
    description = models.TextField(verbose_name="商品详情描述")

    # 自动记录时间
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        db_table = 'product'
        verbose_name = '商品信息'
        verbose_name_plural = verbose_name
        ordering = ['-created_at']

    def __str__(self):
        return f"商品{self.id}(库存:{self.stock})"

三、数据库迁移

注意要在settings.py里注册app哦

1. 生成迁移文件
复制代码
python manage.py makemigrations myapp
2. 查看生成的SQL(可选)
复制代码
python manage.py sqlmigrate myapp 0001
3. 执行迁移
复制代码
python manage.py migrate

示例

1. 首先创建序列化器

serializers.py 中:

复制代码
from rest_framework import serializers
from .models import Product, SpecificationCategory


class SpecificationCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = SpecificationCategory
        fields = ['id', 'name', 'cid']


class ProductSerializer(serializers.ModelSerializer):
    # 保留只读的嵌套表示
    spec_category = SpecificationCategorySerializer(read_only=True)
    # 改为只接受spec_category的ID
    spec_category_id = serializers.PrimaryKeyRelatedField(
        queryset=SpecificationCategory.objects.all(),
        source='spec_category',
        write_only=True
    )

    class Meta:
        model = Product
        fields = [
            'id', 'price', 'stock', 'spec_category',
            'image', 'selling_points', 'description',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['created_at', 'updated_at']

APIView 使用示例

2. 创建 APIView 视图

views.py 中:

复制代码
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Product
from .serializers import ProductSerializer
from django.shortcuts import get_object_or_404


class ProductAPIView(APIView):
    """
    商品API视图,支持列表获取和创建
    """

    def get(self, request, format=None):
        """
        获取所有商品列表
        """
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        创建新商品
        """
        serializer = ProductSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ProductDetailAPIView(APIView):
    """
    商品详情API视图,支持检索、更新和删除单个商品
    """

    def get_object(self, pk):
        return get_object_or_404(Product, pk=pk)

    def get(self, request, pk, format=None):
        """
        获取单个商品详情
        """
        product = self.get_object(pk)
        serializer = ProductSerializer(product)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        """
        更新整个商品信息
        """
        product = self.get_object(pk)
        serializer = ProductSerializer(product, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def patch(self, request, pk, format=None):
        """
        部分更新商品信息
        """
        product = self.get_object(pk)
        serializer = ProductSerializer(product, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        """
        删除商品
        """
        product = self.get_object(pk)
        product.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
3. 配置 URL 路由

urls.py 中:

复制代码
from django.urls import path
from myapp.views import ProductAPIView,ProductDetailAPIView

urlpatterns = [
    path('products/', ProductAPIView.as_view(), name='product-list'),
    path('products/<int:pk>/', ProductDetailAPIView.as_view(), name='product-detail'),
]

访问:

ViewSets的ModelViewSet示例

2. 创建 APIView 视图

views.py 中:

复制代码
from .models import Product,SpecificationCategory
from .serializers import ProductSerializer,SpecificationCategorySerializer
from rest_framework import viewsets


class SpecificationCategoryViewSet(viewsets.ModelViewSet):
    queryset = SpecificationCategory.objects.all()
    serializer_class = SpecificationCategorySerializer

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
3. 配置 URL 路由

urls.py 中:

复制代码
from django.urls import path, include
from myapp.views import *
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('spec-categories', SpecificationCategoryViewSet)
router.register('products_view', ProductViewSet)
urlpatterns = [
    path('api/', include(router.urls)),  # 注意这里包含了路由
]

访问: