I am working on a dynamic form which contained multiple FileFields which could have initial values. The FileInput widget doesn't show initial values since that could expose too much about the servers underlying file system. Despite this I wanted to show the file name as user feedback.
If the form was static, I could pass current file names in through the context and just be very explicit with my template code. Since the form was dynamic the template code would have to iterate though the fields, and there is no easy way to look up unrelated data at the same time.
To learn some nifty tricks on how to create dynamic forms check out So you want a dynamic form on the b-list blog.
Meanwhile I need a solution to pass in the initial file name data with the form. The built in initial dictionary didn't really work, and the field objects initial data member was empty. I had to look outside the form. Beyond the form to the truth: there is not form!
There Is No Form
A pearl of wisdom in my grasp, the form object did not matter, only the field objects were required to render a form. (Assuming you don't need form-wide errors ...)
In the view I passed in 2-uples of the initial file names of the files and the field objects. I did not need to pass the form object into the template at all:
def view(request):
posting = get_object_or_404(Posting, pk=id) # Get the thing the dynamic form depends on
file_store = get_object_or_404(FileStore, pk=id) # Something like this
if request.method == "POST":
file_form = make_file_application_form(posting)(request.POST, request.FILES)
file_fields_and_names = [(file_form[key], getattr(file_store, key)) for key in file_form.fields]
file_fields_and_names = [(field, file_name_from_file_obj(file)) for field,file in file_fields_and_names]
if file_form.is_valid():
file_data = file_form.cleaned_data
for key in file_data:
if file_data[key]:
setattr(file_store, key, file_data[key])
file_store.save()
return redirect("view")
else:
file_form = make_file_application_form(posting)()
file_fields_and_names = [(file_form[key], getattr(file_store, key)) for key in file_form.fields]
file_fields_and_names = [(field, file_name_from_file_obj(file)) for field,file in file_fields_and_names]
return render_to_response(template,
dict(file_fields_and_names=file_fields_and_names, ...),
context_instance=RequestContext(request))
So if you need to, you can get creative with how you pass your fields into your template.