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

如何在Django REST Framework中实现选项随问题动态过滤?

解决Django REST Framework中问题与选项的联动需求

这是表单联动里很常见的场景,要实现「选完问题后只显示对应选项」,得前后端配合来做,我给你两种实用的方案:

方案一:后端动态过滤选项的QuerySet

通过自定义序列化字段,根据请求中的问题参数来动态调整选项的查询范围,适合在DRF的可浏览API里快速测试,或者前端不想额外写太多逻辑的情况。

首先自定义一个继承自SlugRelatedField的字段,重写get_queryset方法:

from rest_framework import serializers
from .models import Option

class DynamicOptionSlugRelatedField(serializers.SlugRelatedField):
    def get_queryset(self):
        # 从请求参数里获取选中的问题ID
        question_id = self.context['request'].query_params.get('question_id')
        queryset = Option.objects.all()
        if question_id:
            # 只返回该问题对应的选项
            queryset = queryset.filter(question_id=question_id)
        return queryset

然后修改你的TestSerializer,把原来的option字段替换成自定义的这个字段:

class TestSerializer(serializers.ModelSerializer):
    question = serializers.SlugRelatedField(queryset=Question.objects.all(), slug_field='question')
    option = DynamicOptionSlugRelatedField(slug_field='option')
    
    class Meta:
        model = UserTest
        fields = ('question', 'option')

注意:使用这个方案时,前端在选择问题后,需要把问题ID作为查询参数(比如?question_id=1)附加到请求里,这样后端就能拿到参数过滤选项了。

方案二:前端主动请求对应选项(更推荐生产环境)

这种方案体验更流畅,用户选完问题后,前端立刻请求该问题的选项列表,再渲染到下拉框里,是实际项目中常用的方式。

第一步:后端新增接口返回指定问题的选项

先写一个API视图来提供某个问题的选项:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Option
from rest_framework import serializers

class QuestionOptionsAPIView(APIView):
    def get(self, request, question_id):
        # 过滤出该问题下的所有选项
        options = Option.objects.filter(question_id=question_id)
        # 序列化选项数据
        serializer = serializers.SlugRelatedField(
            queryset=options,
            slug_field='option',
            many=True
        )
        return Response(serializer.data)

然后在urls.py里配置路由:

from django.urls import path
from .views import QuestionOptionsAPIView

urlpatterns = [
    # 其他路由...
    path('api/questions/<int:question_id>/options/', QuestionOptionsAPIView.as_view(), name='question-options'),
]

第二步:前端实现联动逻辑

这里用原生JavaScript举个例子,Vue/React等框架的思路是一致的:

// 获取页面上的下拉框元素
const questionSelect = document.getElementById('question-select');
const optionSelect = document.getElementById('option-select');

// 先加载所有问题到下拉框
fetch('/api/questions/')
  .then(res => res.json())
  .then(questions => {
    questions.forEach(question => {
      const opt = document.createElement('option');
      opt.value = question.id;
      opt.textContent = question.question;
      questionSelect.appendChild(opt);
    });
  });

// 监听问题选择的变化
questionSelect.addEventListener('change', function() {
  const selectedQuestionId = this.value;
  
  // 如果没选问题,清空选项下拉框
  if (!selectedQuestionId) {
    optionSelect.innerHTML = '<option value="">请先选择问题</option>';
    return;
  }
  
  // 请求该问题对应的选项
  fetch(`/api/questions/${selectedQuestionId}/options/`)
    .then(res => res.json())
    .then(options => {
      // 清空原有选项,添加新选项
      optionSelect.innerHTML = '<option value="">请选择选项</option>';
      options.forEach(option => {
        const opt = document.createElement('option');
        opt.value = option.id;
        opt.textContent = option.option;
        optionSelect.appendChild(opt);
      });
    });
});

额外提示

另外,你的UserTest模型里有user字段,创建记录时记得自动关联当前登录用户,避免手动输入:

from rest_framework import viewsets

class UserTestViewSet(viewsets.ModelViewSet):
    serializer_class = TestSerializer
    queryset = UserTest.objects.all()
    
    def perform_create(self, serializer):
        # 保存时自动设置当前用户
        serializer.save(user=self.request.user)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:32:51