Queryset in ModelForm is properly limited initially, but not when form is submitted with errors

StackOverflow https://stackoverflow.com/questions/17845764

  •  04-06-2022
  •  | 
  •  

Domanda

I want to limit a queryset for a form based on the user sending the request. I am having some trouble getting a ModelForm to properly limit the queryset of a field when the form is submitted but invalid. The form gets redisplayed with the error text, but no longer has the queryset limited. What could be the cause here?

models.py

from django.db import models
from django.contrib.auth.models import User

class Patient(models.Model):
    name = models.CharField(max_length=100)
    doctor = models.ForeignKey(User)
    def __unicode__(self):
        return self.name

class Prescription(models.Model):
    name = models.CharField(max_length=100)
    patient = models.ForeignKey(Patient)

views.py

import medical.models as models
import medical.forms as forms
from django.shortcuts import render

def add_form(request):
    if request.method == 'POST':
        form = forms.PrescriptionForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = forms.make_prescription_form(request.user)
    return render(request, 'add_form.html', {'form': form})

forms.py

import medical.models as models
from django.forms import ModelForm, ModelChoiceField

class PrescriptionForm(ModelForm):
    class Meta:
        model = models.Prescription

def make_prescription_form(dr):
    class PrescriptionForm(ModelForm):
        patient = ModelChoiceField(queryset=models.Patient.objects.filter(doctor=dr))
        class Meta:
            model = models.Prescription
    return PrescriptionForm

add_form.html

{{ request.user.first_name }}
{% if form.errors %}
<p style="color: red;">Please correct the error{{ form.errors|pluralize }} below.</p>
{% endif %}

<form action="" method="post">{% csrf_token %}
     {{ form }}
     <br>
     <input type="submit" value="Submit">
</form>

I would greatly appreciate any help with this, or suggestion on a better way to achieve the same thing! Let me know if any more files would be helpful. I'm using Django 1.3.

È stato utile?

Soluzione

First off, it looks like you left off a bit - make_prescription_form returns a class, not a form instance, and you're passing the class directly to the rendering in the GET path. I am assuming that's a typo.

You're not using your make_prescription_form wrapper in the POST path. The smallest change from this implementation would be:

def add_form(request):
    form_class = forms.make_prescription_form(request.user)
    if request.method == 'POST':
        form = form_class(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = form_class()
    return render(request, 'add_form.html', {'form': form})

As for other ways to do this - you can just set the form field's queryset directly in your view.

forms.py
class PrescriptionForm(ModelForm):
    class Meta:
        model = models.Prescription

views.py
def add_form(request):
    if request.method == 'POST':
        form = PrescriptionForm(request.POST)
        form.fields['patient'].queryset = models.Patient.objects.filter(doctor=request.user)
        if form.is_valid():
            form.save()
    else:
        form = PrescriptionForm()
        form.fields['patient'].queryset = models.Patient.objects.filter(doctor=request.user)
    return render(request, 'add_form.html', {'form': form})

Or set doctor as an argument to PrescriptionForm's __init__ and update the queryset there:

forms.py
class PrescriptionForm(ModelForm):
    class Meta:
        model = models.Prescription

    def __init__(self, *args, doctor=None, **kwargs):
        super(PrescriptionForm, self).__init__(*args, **kwargs)
        if self.doctor is not None:
            self.fields['patient'] = models.Patient.objects.filter(doctor=doctor)

views.py
def add_form(request):
    if request.method == 'POST':
        form = PrescriptionForm(request.POST, doctor=request.user)
        if form.is_valid():
            form.save()
    else:
        form = PrescriptionForm(doctor=request.user)
    return render(request, 'add_form.html', {'form': form})                
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top