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

如何在不提前验证的前提下动态筛选Django ModelForm选项?

Fixing Dynamic Form Filtering and Validation for Your SampleRunSearchForm

I’ve run into this exact issue before—when you dynamically populate form fields based on context from the GET request, you need to make sure that context is also available during POST validation. Here’s how to fix your setup:

Step 1: Refactor the Form to Use ModelMultipleChoiceField

Instead of manually creating a ChoiceField, use ModelMultipleChoiceField—it’s built for selecting multiple model instances and handles queryset filtering/validation seamlessly:

# forms.py
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Field, Submit
from .models import SampleRun

class SampleRunSearchForm(forms.ModelForm):
    class Meta:
        model = SampleRun
        fields = ('id',)

    def __init__(self, sr_obj=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Populate the field with filtered samples if sr_obj is provided
        if sr_obj is not None:
            self.fields['id'] = forms.ModelMultipleChoiceField(
                queryset=sr_obj,
                required=True,
                label='Sample:',
                widget=forms.CheckboxSelectMultiple,
            )
        
        # Keep your crispy forms setup
        self.helper = FormHelper()
        self.helper.layout = Layout(
            Field('id', css_class='sample-run-display',),
            Submit('submit', 'Report samples', css_class='upload-btn')
        )
        self.helper.form_method = 'POST'

Step 2: Share Context Between GET and POST in the View

The main problem was that your POST method wasn’t retrieving the filtered sample_run_obj before initializing the form. Let’s refactor the view to reuse the context-fetching logic:

# views.py
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.views import View
from .forms import SampleRunSearchForm
from .models import Run

class SearchSampleRun(View):
    samplerunform = SampleRunSearchForm
    template_name = 'results/samplerun_search_form.html'

    def _get_filtered_samples(self, kwargs):
        """Reusable method to get context objects for both GET and POST"""
        self.run_obj = get_object_or_404(Run, id=kwargs['run_id'])
        self.choice = kwargs['choice']
        return self.obtainCorrectSamples()  # Your existing filtering method

    def get(self, request, *args, **kwargs):
        sample_run_obj = self._get_filtered_samples(kwargs)
        samplerunform = self.samplerunform(sr_obj=sample_run_obj)
        return render(request, self.template_name, {'samplerunform': samplerunform})

    def post(self, request, *args, **kwargs):
        sample_run_obj = self._get_filtered_samples(kwargs)
        # Pass both the filtered queryset AND POST data to the form
        samplerunform = self.samplerunform(sr_obj=sample_run_obj, data=request.POST)
        
        if samplerunform.is_valid():
            # Access selected samples with samplerunform.cleaned_data['id']
            selected_samples = samplerunform.cleaned_data['id']
            # Redirect to your results page
            return HttpResponseRedirect(f'/results/{self.run_obj.id}/')
        
        # If invalid, re-render the form with errors and preserved checkboxes
        return render(request, self.template_name, {'samplerunform': samplerunform})

Why This Works

  1. Form Initialization: The form now accepts sr_obj as an optional parameter. When provided, it replaces the default id field with a ModelMultipleChoiceField using your filtered queryset.
  2. Shared Context: The _get_filtered_samples method ensures both GET and POST requests use the same logic to fetch your filtered SampleRun objects. This means the form always has access to the valid choices during validation.
  3. Proper Validation: By passing sr_obj to the form during POST, the form can validate that the submitted IDs are actually part of the filtered set—preventing invalid submissions and keeping the checkbox list intact if validation fails.

Content of the question来源于stack exchange,提问作者trouselife

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:07:03