You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在DRF中通过关联Deck ID获取Progress对象并实现CRUD

解决方案

一、通过Deck ID获取Progress对象的实现

方法1:修改ViewSet的Lookup逻辑(推荐)

直接调整ProgressViewSet的查找规则,让它通过deck_id定位Progress对象,这样就能通过http://localhost/api/v1/progress/<deck_id>/访问目标资源:

from django.shortcuts import get_object_or_404
from rest_framework import viewsets

class ProgressViewSet(viewsets.ModelViewSet):
    queryset = Progress.objects.all()
    serializer_class = ProgressSerializer
    permission_classes = (OwnerOrAdminProgress,)
    # 将查找字段指定为deck_id
    lookup_field = 'deck_id'
    http_method_names = ['get', 'post', 'patch', 'delete']

    def get_object(self):
        # 重写对象获取逻辑,通过deck_id匹配Progress
        deck_id = self.kwargs.get(self.lookup_field)
        return get_object_or_404(Progress, deck_id=deck_id)

配置完成后,访问/api/v1/progress/1/即可获取对应deck_id=1的Progress对象,同时不影响原有CRUD接口的正常运行。

方法2:自定义ViewSet动作

如果不想修改默认查找规则,可以添加一个独立的自定义动作,通过专属端点获取:

from rest_framework.decorators import action
from rest_framework.response import Response
from django.shortcuts import get_object_or_404

class ProgressViewSet(viewsets.ModelViewSet):
    # 保留原有代码...

    @action(detail=False, url_path='by-deck/(?P<deck_id>[^/.]+)')
    def by_deck(self, request, deck_id=None):
        progress = get_object_or_404(Progress, deck_id=deck_id)
        serializer = self.get_serializer(progress)
        return Response(serializer.data)

此时访问/api/v1/progress/by-deck/1/即可获取对应Deck的Progress对象。

二、完善完整CRUD功能

1. 修复模型必填字段

补充Progress模型中OneToOneField的on_delete参数(Django强制要求):

class Progress(models.Model):
    deck = models.OneToOneField(Deck, on_delete=models.CASCADE)  # 添加on_delete参数
    progress = models.JSONField(null=True)

2. 优化序列化器

如果希望返回Deck的详细信息而非仅ID,可以使用嵌套序列化器,同时支持创建时传入deck_id:

from rest_framework import serializers
from .models import Deck, Progress

class DeckSerializer(serializers.ModelSerializer):
    class Meta:
        model = Deck
        fields = ('id', 'name', 'owner')

class ProgressSerializer(serializers.ModelSerializer):
    deck = DeckSerializer(read_only=True)  # 嵌套返回Deck详情
    deck_id = serializers.PrimaryKeyRelatedField(queryset=Deck.objects.all(), write_only=True)  # 创建时传入deck_id

    class Meta:
        model = Progress
        fields = ('id', 'deck', 'deck_id', 'progress')

    def create(self, validated_data):
        # 剥离deck_id并关联到Progress实例
        deck_id = validated_data.pop('deck_id')
        return Progress.objects.create(deck_id=deck_id, **validated_data)

3. 完善权限控制

确保OwnerOrAdminProgress权限类正确校验用户权限,示例实现:

from rest_framework import permissions

class OwnerOrAdminProgress(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        # 管理员拥有所有操作权限
        if request.user.is_staff:
            return True
        # 仅允许Deck的所有者访问对应的Progress
        return obj.deck.owner == request.user

4. CRUD接口验证

配置完成后,以下接口均能正常工作:

  • 创建Progress:POST /api/v1/progress/,请求体传入deck_id和progress字段
  • 获取单个Progress:GET /api/v1/progress/<deck_id>/(方法1)或GET /api/v1/progress/by-deck/<deck_id>/(方法2)
  • 更新Progress:PATCH /api/v1/progress/<deck_id>/,传入需要修改的progress字段
  • 删除Progress:DELETE /api/v1/progress/<deck_id>/
  • 获取所有Progress(限管理员/有权限用户):GET /api/v1/progress/

三、其他可选方案

  • 通过Deck接口嵌套获取:在DeckViewSet中添加自定义动作,实现访问/api/v1/decks/<deck_id>/progress/直接获取关联的Progress对象
  • 使用过滤参数:借助django-filter库,通过/api/v1/progress/?deck_id=1的方式过滤获取目标Progress

内容的提问来源于stack exchange,提问作者CarloDiPalma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:57:31