Overridding model formset queryset in BaseModelFormSet
|Reported by:||Owned by:||nobody|
|Cc:||Triage Stage:||Ready for checkin|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
In https://docs.djangoproject.com/en/1.3/topics/forms/modelforms/#changing-the-queryset there are two methods described to override default queryset. Second method won't work in Django 1.3:
from django.forms.models import BaseModelFormSet class BaseAuthorFormSet(BaseModelFormSet): def __init__(self, *args, **kwargs): super(BaseAuthorFormSet, self).__init__(*args, **kwargs) self.queryset = Author.objects.filter(name__startswith='O')
Calling BaseModelFormSet __init__ will call BaseFormSet's __init__ and it will in turn call self._construct_forms(). self._construct_forms use queryset we try to override but it will be to late for this when the program reach our self.queryset = Author.objects.filter(name__startswith='O') line.
BaseFormSet's _construct_forms is only called once to populate forms attribute. We can defer it a bit using properties to allow queryset to be overridden. So instead for:
def _construct_forms(self): # instantiate all the forms and put them in self.forms self.forms =  for i in xrange(self.total_form_count()): self.forms.append(self._construct_form(i))
we can do:
def _construct_forms(self): if hasattr(self, "_forms"): return self._forms # instantiate all the forms and put them in self.forms self._forms =  for i in xrange(self.total_form_count()): self._forms.append(self._construct_form(i)) return self._forms forms = property(_construct_forms)
This change will also require _construct_forms call to be removed from BaseFormSet's __init__.
Deferring forms creation should give us some time to override queryset attribute in BaseAuthorFormSet's __init__.