Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django class based view ListView with form

Tags:

django

views

The main view is a simple paginated ListView and I want to add a search form to it.

I thought something like this would do the trick:

class MyListView(ListView, FormView):     form_class = MySearchForm     success_url = 'my-sucess-url'     model = MyModel     # ... 

But apparently I got it wrong .. and I can't find how to do it in the official documentation.

Suggestions ?

like image 738
h3. Avatar asked Jun 20 '11 03:06

h3.


People also ask

How do you use class-based views in Django?

For Django class-based views we access an appropriate view function by calling the class method as_view() . This does all the work of creating an instance of the class, and making sure that the right handler methods are called for incoming HTTP requests.

How do you use decorators in class-based view in Django?

To decorate every instance of a class-based view, you need to decorate the class definition itself. To do this you apply the decorator to the dispatch() method of the class. The decorators will process a request in the order they are passed to the decorator.

What is Object_list in Django?

object_list will contain the list of objects (usually, but not necessarily a queryset) that the view is operating upon. Ancestors (MRO) This view inherits methods and attributes from the following views: django.

What is Form_valid in Django?

Model form views provide a form_valid() implementation that saves the model automatically. You can override this if you have any special requirements; see below for examples. You don't even need to provide a success_url for CreateView or UpdateView - they will use get_absolute_url() on the model object if available.


2 Answers

These answers have helped so much to steer me in the right direction. Thank guys.

For my implementation I needed a form view that returned a ListView on both get and post. I don't like having to repeat the contents of the get function but it needed a couple of changes. The form is now available from get_queryset now too with self.form.

from django.http import Http404 from django.utils.translation import ugettext as _ from django.views.generic.edit import FormMixin from django.views.generic.list import ListView  class FormListView(FormMixin, ListView):     def get(self, request, *args, **kwargs):         # From ProcessFormMixin         form_class = self.get_form_class()         self.form = self.get_form(form_class)          # From BaseListView         self.object_list = self.get_queryset()         allow_empty = self.get_allow_empty()         if not allow_empty and len(self.object_list) == 0:             raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")                           % {'class_name': self.__class__.__name__})          context = self.get_context_data(object_list=self.object_list, form=self.form)         return self.render_to_response(context)      def post(self, request, *args, **kwargs):         return self.get(request, *args, **kwargs)   class MyListView(FormListView):     form_class = MySearchForm     model = MyModel     # ... 
like image 57
AgentK Avatar answered Sep 16 '22 15:09

AgentK


I've been seaching for a proper solution too. But I could not find any so had to come up with my own.

views.py

class VocationsListView(ListView):      context_object_name = "vocations"     template_name = "vocations/vocations.html"     paginate_by = 10      def get_queryset(self):         get = self.request.GET.copy()         if(len(get)):             get.pop('page')         self.baseurl = urlencode(get)         model = Vocation         self.form = SearchForm(self.request.GET)         filters = model.get_queryset(self.request.GET)         if len(filters):             model = model.objects.filter(filters)         else:             model = model.objects.all()         return model    def get_context_data(self):     context = super(VocationsListView, self).get_context_data()     context['form'] = self.form     context['baseurl']= self.baseurl     return context 

models.py

class Vocation(models.Model):     title = models.CharField(max_length = 255)     intro = models.TextField()     description = models.TextField(blank = True)     date_created = models.DateTimeField(auto_now_add = True)     date_modified = models.DateTimeField(auto_now = True)     created_by = models.ForeignKey(User, related_name = "vocation_created")     modified_by = models.ForeignKey(User, related_name = "vocation_modified")      class Meta:         db_table = "vocation"      @property     def slug(self):         return defaultfilters.slugify(self.title)      def __unicode__(self):         return self.title      @staticmethod     def get_queryset(params):          date_created = params.get('date_created')         keyword = params.get('keyword')         qset = Q(pk__gt = 0)         if keyword:             qset &= Q(title__icontains = keyword)         if date_created:             qset &= Q(date_created__gte = date_created)         return qset 

so basically I add this piece of code to every model class, where I want implement the search functionality. This is because filters for the every model have to be prepared explicitly

@staticmethod def get_queryset(params):      date_created = params.get('date_created')     keyword = params.get('keyword')     qset = Q(pk__gt = 0)     if keyword:         qset &= Q(title__icontains = keyword)     if date_created         qset &= Q(date_created__gte = date_created)     return qset 

it prepares the qset filter that I use to retrieve the data from the model

like image 42
Azamat Tokhtaev Avatar answered Sep 20 '22 15:09

Azamat Tokhtaev