Christopher Dodd
unread,Apr 15, 2009, 4:40:48 PM4/15/09Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Django users
Once I populated my database with thousands and thousands of rows the
widgets available for manipulating the data on the Admin site became
virtually unusable.
So I have written a custom forms.Field that is a simple TextField that
maps to a (hopefully) unique char field on a Model. The Field
validates that the text maps to a single entry in the model, and
provides a function that can be called from the Form that will reset
the field's initial value to be the unique field (rather than the pk
id).
This has major speed and some usability advantages over the existing
widgets/fields.
It works pretty well, but I'm not so keen on the code and would
appreciate advice for cleaning it up and making it easier to use. I
especially don't like having to call fix_initial_form_value() from the
form. Are there better ways to do this?
Here is the custom Field code, followed by an example using it.
#
# A Field that acts as a TextField but must match an entry in the
given
# queryset/field.
#
class ModelChoiceTextField(forms.Field):
def __init__(self, model, unique_field_name, attrs=None, *args,
**kwargs):
kwargs['widget'] = forms.widgets.TextInput(attrs)
super(ModelChoiceTextField, self).__init__(*args, **kwargs)
self.queryset = model.objects
self.unique_field_name = unique_field_name
def clean(self, value):
if not value and not self.required:
return None
try:
return self.queryset.get(**{self.unique_field_name: value})
except self.queryset.model.DoesNotExist:
raise forms.ValidationError("Please enter a valid %s." %
(self.queryset.model._meta.verbose_name,))
except self.queryset.model.MultipleObjectsReturned:
raise forms.ValidationError("Please enter a unique %s." %
(self.queryset.model._meta.verbose_name,))
#
# Change the form's intial value for this field to it's chosen
# member of the object.
#
# This assumes the field is for a Foriegn key and the initial
value will
# be a pk.
#
def fix_initial_form_value(self, form, field_name):
if field_name in form.initial and form.initial[field_name]:
obj = self.queryset.get(**{'pk': form.initial[field_name]})
form.initial[field_name] = getattr(obj, self.unique_field_name)
Example usage:
class PackageFileForm(forms.ModelForm):
file = ModelChoiceTextField(OSFile,
unique_field_name='file_name',
attrs={'size':'60'})
def __init__(self, *args, **kwargs):
super(ArgusPackageFileForm, self).__init__(*args, **kwargs)
self.fields['file'].fix_initial_form_value(self, 'file')
I'd also like for the field to set the 'required' flag automagically
based on its field's 'blank' flag. But that may not be doable in the
Field?
Advice, comments and ideas welcome.
Thanks,
Chris Dodd