【后端】【django drf】Django DRF API 编写规范(程序设计规则)

Django DRF API 编写规范(程序设计规则)

为了确保 Django DRF 代码的可维护性、可扩展性和高质量,API 设计不仅要符合 RESTful 规范,还需要遵循一定的程序设计规则。以下是一些关键的编写规范,以保证代码的清晰性、可读性和稳定性。


一、代码组织与结构

(一)项目目录结构

建议遵循 Django 的最佳实践,将 API 代码模块化,保持清晰的层次结构:

复制代码
my_project/
│── my_app/
│   │── models.py          # 数据模型
│   │── serializers.py     # 序列化器
│   │── views.py          # 视图
│   │── urls.py           # 路由
│   │── permissions.py    # 权限
│   │── paginations.py    # 分页
│   │── filters.py        # 过滤器
│   │── services.py       # 业务逻辑
│   └── tests/            # 单元测试
│── config/
│   │── settings.py       # 项目配置
│   │── urls.py           # 主路由
│── manage.py
  • models.py:定义数据库模型
  • serializers.py:定义数据序列化逻辑
  • views.py:编写 API 逻辑
  • permissions.py:自定义权限
  • paginations.py:自定义分页逻辑
  • filters.py:定义过滤器
  • services.py:封装业务逻辑,避免视图代码膨胀
  • tests/:单元测试,提高代码质量

二、视图层规范

(一)优先使用 ViewSet

避免 APIView,尽可能使用 ModelViewSet 来减少代码重复:

python 复制代码
from rest_framework.viewsets import ModelViewSet
from .models import User
from .serializers import UserSerializer

class UserViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

如果 ViewSet 过重,可以拆分逻辑到 services.py,避免过多业务逻辑混杂在视图层。

(二)限制 ViewSet 的 HTTP 方法

如果某个 ViewSet 只需要支持部分 HTTP 方法,应在 viewset 里限制:

python 复制代码
class UserViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    http_method_names = ['get', 'post', 'patch', 'delete']

三、序列化器(Serializers)规范

(一)使用 ModelSerializer

尽可能使用 ModelSerializer,减少重复代码:

python 复制代码
from rest_framework import serializers
from .models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "username", "email", "created_at"]

(二)避免 serializers.Serializer 直接定义字段

除非是特殊业务数据结构,否则不推荐手写字段:

python 复制代码
# ❌ 不推荐
class CustomSerializer(serializers.Serializer):
    username = serializers.CharField()
    email = serializers.EmailField()

尽量使用 ModelSerializer 直接绑定模型,减少维护成本。

(三)字段验证逻辑放在 validate_xxx

python 复制代码
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "username", "email"]

    def validate_email(self, value):
        if "spam" in value:
            raise serializers.ValidationError("Email contains spam content")
        return value

四、业务逻辑拆分(Services 层)

为了避免 views.py 代码过于庞大,建议将业务逻辑封装到 services.py

python 复制代码
# services.py
def create_user(username, email):
    if User.objects.filter(email=email).exists():
        raise ValueError("Email already exists")
    return User.objects.create(username=username, email=email)

然后在 views.py 里调用:

python 复制代码
from .services import create_user

class UserViewSet(ModelViewSet):
    ...
    def perform_create(self, serializer):
        create_user(serializer.validated_data["username"], serializer.validated_data["email"])

五、权限控制(Permissions)

(一)尽可能使用 permissions.py 单独管理权限

避免直接在 views.py 里写权限判断,而是使用 Django DRF 的 permissions 机制:

python 复制代码
from rest_framework.permissions import BasePermission

class IsAdminUserOrReadOnly(BasePermission):
    def has_permission(self, request, view):
        if request.method in ['GET']:
            return True
        return request.user and request.user.is_staff

然后在 views.py 里使用:

python 复制代码
class UserViewSet(ModelViewSet):
    permission_classes = [IsAdminUserOrReadOnly]

六、查询优化

避免 N+1 查询:

python 复制代码
class UserViewSet(ModelViewSet):
    queryset = User.objects.select_related("profile").all()

(二)使用分页减少数据库压力

配置全局分页:

python 复制代码
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

七、异常处理

(一)全局异常处理

exception_handler.py 里统一管理异常:

python 复制代码
from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is not None:
        response.data = {
            "code": response.status_code,
            "message": response.data.get("detail", "An error occurred")
        }
    return response

settings.py 里配置:

python 复制代码
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_app.exception_handler.custom_exception_handler'
}

八、单元测试(Tests)

(一)测试 API 逻辑

编写 pytest 测试,确保 API 可用:

python 复制代码
import pytest
from rest_framework.test import APIClient

@pytest.mark.django_db
def test_create_user():
    client = APIClient()
    response = client.post("/api/users/", {"username": "john", "email": "[email protected]"})
    assert response.status_code == 201

(二)覆盖率标准

使用 pytest 运行测试,并确保代码覆盖率:

bash 复制代码
pytest --cov=my_app

总结

  1. 遵循 Django 项目目录结构,保持模块化设计
  2. 使用 ViewSet 处理 API 逻辑,并限制 HTTP 方法
  3. 优先使用 ModelSerializer,避免重复字段定义
  4. 业务逻辑拆分到 services.py,避免 views.py 代码过重
  5. 权限控制统一放在 permissions.py,避免手写权限逻辑
  6. 使用 select_relatedprefetch_related 进行查询优化
  7. 使用 custom_exception_handler 统一异常处理
  8. 编写 pytest 单元测试,确保代码稳定

通过这些规则,可以提升 Django DRF API 的可维护性、扩展性和高效性,使代码更加清晰易读。

相关推荐
牛奔17 分钟前
Linux 安装配置Anaconda
python·conda
往日情怀酿做酒 V176392963820 分钟前
Django项目之订单管理part3
后端·python·django
查理零世39 分钟前
【算法】 区间合并(附蓝桥杯真题) python
python·算法·蓝桥杯
人工智能研究所1 小时前
使用OpenCV与Python编写自己的俄罗斯方块小游戏
开发语言·python·opencv
DDD小小小宇宙1 小时前
python列表基础知识
开发语言·windows·python
@黄色海岸2 小时前
【sklearn 05】sklearn功能模块
人工智能·python·sklearn
追逐☞2 小时前
PyTorch使用-张量类型转换
人工智能·pytorch·python
懒大王爱吃狼2 小时前
Python + Qt Designer构建多界面GUI应用程序:Python如何调用多个界面文件
开发语言·数据库·python·qt·mysql·python基础·命令模式
北京_宏哥2 小时前
🔥《手把手教你》系列练习篇之8-python+ selenium自动化测试(详细教程)
前端·python·selenium
北京_宏哥2 小时前
🔥《手把手教你》系列练习篇之7-python+ selenium自动化测试(详细教程)
前端·python·selenium