class AjaxAutoSelect(forms.Select):
"""
May not work for all possible widget types for the related field
(simple html form widgets should be okay, we listen to jQuery 'change' event)
"""
related_field = ''
def render(self, name, value, attrs=None, choices=()):
self._element_id = attrs['id']
# normal widget output from the ancestor
# create a field with a dummy name, the real value
# will be retrieved from a hidden field
parent_output = super(AjaxAutoSelect, self).render("dummy-%s" % name, value, attrs, choices)
# output
if value is None:
value = ''
mapping = {
"related_field": self.related_field,
"parent_output": parent_output,
"name": name,
"element_id": self._element_id,
"value": value,
'app_label': self.model._meta.app_label,
'object_name': self.model._meta.object_name,
'select_related': self.select_related,
}
# TO DO:
# we shouldn't SelectBox.empty() if we're editing an existing record that has a value in the related field
output = u"""
%(parent_output)s
""" % mapping
return mark_safe(output)
class AjaxFilteredForeignKeyField(forms.ModelChoiceField):
def __init__(self, model, field_name, widget=AjaxAutoSelect, *args, **kwargs):
queryset = model.objects.none()
super(AjaxFilteredForeignKeyField, self).__init__(queryset, widget=widget, *args, **kwargs)
self.isFilteredForeignKeyField = True
self.widget.model = self.model = model
self.widget.related_field = self.related_field = field_name
self.widget.select_related = None
class AjaxFilteredFKFieldsForm(forms.ModelForm):
def __init__(self, initial=None, *args, **kwargs):
super(AjaxFilteredFKFieldsForm, self).__init__(initial=initial, *args, **kwargs)
for field_name in self.fields:
field = self.fields[field_name]
if getattr(field, 'isFilteredForeignKeyField', False):
if field.related_field in self.initial:
# sometimes it's a list with one member, sometimes it's just a number (awesome!)
try:
fk_val = self.initial.get(field.related_field, self.fields[field.related_field].initial)[0]
except TypeError:
fk_val = self.initial.get(field.related_field, self.fields[field.related_field].initial)
fargs = {'%s__pk'%field.related_field: fk_val}
field.queryset = field.model.objects.filter(**fargs)