Opened 4 years ago

Closed 4 years ago

#17740 closed Bug (needsinfo)

BaseModelFormSet should use its queryset when initializing the ModelForm's pk_field's ModelChoiceField.

Reported by: larsent Owned by: larsent
Component: Forms Version: 1.3
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


BaseModelFormSet uses the queryset of the default model manager when creating the ModelChoiceField for the model's pk_field.

Line 656:

if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
    qs =
    qs = self.model._default_manager.get_query_set()
qs = qs.using(form.instance._state.db)
form.fields[] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)

The ModelFormSet will not validate if it is initialized with a queryset containing objects that are not in the model's default manager's queryset.

Change History (2)

comment:1 Changed 4 years ago by larsent

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Code to reproduce this:

#create a ModelFormset with a queryset containing objects not in the default queryset 
MyFormSet = modelformset_factory(ModelA, form=ModelAForm, extra=0)
qs = ModelA.custom_manager_objects.all() #not the default manager. contains objects not in the default manager's queryset
fs = MyFormSet(request.POST, request.FILES, queryset=qs) #fs won't validate 

comment:2 Changed 4 years ago by aaugustin

  • Resolution set to needsinfo
  • Status changed from new to closed

Let me elaborate a bit on the bug report; it's terse and it took me a while to figure out what's going on.

BaseModelFormSet.add_fields(self, form, index) adds a field that contains the primary key to form. This field is invisible to the end user -- it uses a HiddenInput widget -- but it's necessary for Django to know which instance of the model form deals with, when it received the contents of form in the next request. Django uses a ModelChoiceField for this extra field: this makes sense for designating which instance the form applies to, among all existing instances of the model.

"All existing instances of the model" is qs = self.model._default_manager.get_query_set(). By definition -- and unless I missed something -- this queryset always contains all instances of the model. Could you explain how it's possible for your custom_manager to contain an object that isn't in _default_manager?

Note: See TracTickets for help on using tickets.
Back to Top