Search code examples
djangodjango-forms

Pass an initial value to a Django form field


I'm trying to write a search form and maintain the state of the input box between the search request and the search results.

Here's my form:

class SearchForm(forms.Form):
    q = forms.CharField(label='Search: ', max_length=50)

And here's my views code:

def search(request, q=""):
    if (q != ""): 
        q = q.strip()
        form = SearchForm(initial=q) 
        #get results here...
        return render_to_response('things/search_results.html',
          {'things': things,  'form': form, 'query': q})
    elif (request.method == 'POST'): # If the form has been submitted
        form = SearchForm(request.POST) 
        if form.is_valid(): 
          q = form.cleaned_data['q']
          # Process the data in form.cleaned_data
          return HttpResponseRedirect('/things/search/%s/' % q) # Redirect after POST
        else:
          form = SearchForm() 
          return render_to_response('things/search.html', {
            'form': form,
          })
    else:
        form = SearchForm()
        return render_to_response('things/search.html', {
            'form': form,
        })

But this gives me the error:

Caught an exception while rendering: 'unicode' object has no attribute 'get'

How can I pass the initial value? Various things I've tried seem to interfere with the request.POST parameter.


Solution

  • Several things are not good here...

    1) The recommended thing after a POST is to redirect. This avoids the infamous popup saying that you are resubmitting the form when using the back button.

    2) You don't need to say if request.method == 'POST', just if request.POST. That makes your code easier to read.

    3) The view generally looks something like:

    def myview(request):
        # Some set up operations
        if request.POST:
           form=MyForm(request.POST)
           if form.is_valid():
              # some other operations and model save if any
              # redirect to results page
        form=MyForm()
        #render your form template
    

    That is not to say that there can't be much simpler and much more complicated views. But that is the gist of a view: if request is post process the form and redirect; if request is get render the form.

    I don't know why you are getting an unicode error. I can only think that it is related to one of your models that you don't provide. The error, as spookylukey mentions is in his comment, most likely is caused by you submitting a string instead of a dict to the initial parameter.

    I really recommend the django documentation, in particular the tutorial., but there is also the very nice Django Book.

    All that said, I think you want something like:

    def search(request, q=None):
        if request.POST:
            form = SearchForm(request.POST) 
            if form.is_valid(): 
               q = form.cleaned_data['q']
               url=reverse('search_results', args=(q,))
               return HttpResponseRedirect(url)
        if q is None:
            form = SearchForm() 
        else: 
            form = SearchForm(initial={'q': q})
        return render_to_response('things/search.html', {
            'form': form,
        })
    

    Notice that the parameter to initial is a dict of the field values of your form.

    Hope that helps.