JohnJ
JohnJ

Reputation: 7056

passing data between class based forms

I am fairly new to Django and class based forms, and I am having trouble understanding how these interact with each other. Following from the django project example, I have tried to build a "search form", which would sit on all pages of my project:

# forms.py
from django import forms

class SearchForm(forms.Form):
    myquery = forms.CharField(max_length=255,label="", help_text="sq")

    def __unicode__(self):
        return self.myquery

# views.py
from searchapp.forms import SearchForm
from django.views.generic.edit import FormView
from django.views.generic import TemplateView

class SearchView(FormView):
    template_name = 'index.html'
    form_class = SearchForm
    success_url = '/searchres/'

    def form_valid(self, form):
        thequery=form.cleaned_data.get('myquery')
        return super(SearchView, self).form_valid(form)

    class Meta:
        abstract = True

class SearchResView(SearchView):
    template_name = 'searchres.html'


#urls.py
from django.conf.urls import patterns, include, url
from django.conf import settings
from deals.views import IndexView
from searchapp.views import SearchView, SearchResView

urlpatterns = patterns('',
    url(r'^index/', SearchView.as_view(),name="home"),
    url(r'^searchres/', SearchResView.as_view(),name="searchresx"),
)

The plan is the start off with a simple form for user to enter the search query, and also show the input form on the results page. I have the following questions here (sorry - I am a Django newbie esp. to Class Based Views):

Thank you in advance - I am hoping to learn more.

Upvotes: 1

Views: 2178

Answers (1)

Aidan Ewen
Aidan Ewen

Reputation: 13328

I would suggest using function based views for this. If you choose to subclass a generic view you will need to dig through a lot of documentation and possibly source code, to find the right methods to override. (If you're really keen then look at the ListView class along with the get_queryset(), get() and post() methods)

A single django view will normally handle both rendering the empty form AND processing the submitted form.

So the search page (both the form and the results), live at http://your-site.com/search. Your url conf is -

urlpatterns = patterns('',
    #...
    (r'^search/$', 'searchapp.views.search'),
)

And your view looks something like this -

def search(request):
    if request.method == 'POST':
        form = SearchForm(request.POST)
        if form.is_valid():
            my_query = form.cleaned_data['myquery']
            object_list = YourModel.objects.filter(# some operation involving my_query)
            return render_to_response('search_results.html', {'object_list': object_list})
     else:
        form = SearchForm()
     render_to_response('search_form.html', {'form': form})

(Note I've assumed your form method is post rather than get - I know this isn't great http but it's a common pattern with django)

To respond to your questions -

  1. Don't use your own method for cleaning data. Add a clean_myquery method to your form and access it with form.fields['myquery'].clean() (or if you've called is_valid() on your form, it's accessible with just form.cleaned_data['myquery']).

You want to try and avoid passing data for processing to the template. Do as much processing as you can in the view, then render the template. However if you want to pass myquery as a string for the template to render, then add it in to the context dictionary (the second non-key-word argument) in render_to_response -

return render_to_response('search.html', {'object_list': object_list, 'myquery': my query})
  1. The post data is constructed from the form fields. You don't have a form field thequery. The view is processing the POST data - it's not creating it that's done by the html (which in turn is constructed by the Form class). Your variable thequery is declared in the view.

  2. Django's URL dispatcher ignores query strings in the URL so http://your_site.com/ssearch will be processed by the same view as http://your_site.com/search?myquery=findstuff. Simply change the html in the template from <form method='post'> to and access the data in django with request.GET. (You'll need to change the code from the view I described above to include a new check to see whether you're dealing with a form submission or just rendering a blank form)

Have a good read of the docs on views, forms and the url dispatcher.

Upvotes: 1

Related Questions