[ACCEPTED]-Django class based view ListView with form-views
These answers have helped so much to steer 7 me in the right direction. Thank guys.
For 6 my implementation I needed a form view that 5 returned a ListView on both get and post. I 4 don't like having to repeat the contents 3 of the get function but it needed a couple 2 of changes. The form is now available from 1 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
# ...
I've been seaching for a proper solution 8 too. But I could not find any so had to 7 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 6 piece of code to every model class, where 5 I want implement the search functionality. This 4 is because filters for the every model have 3 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 2 qset filter that I use to retrieve the data 1 from the model
In Django 2.2 you can do this (it works 3 fine at least with a get
-request):
from django.views.generic import ListView
from django.views.generic.edit import FormMixin
from .models import MyModel
from .forms import MySearchForm
class ListPageView(FormMixin, ListView):
template_name = 'property_list.html'
model = MyModel
form_class = MySearchForm
queryset = MyModel.objects.all()
Use the FormMixin
before 2 the ListView
. If you want to use the SearchForm
in a TemplateView
you 1 can do this:
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormMixin
from .models import MyModel
from .forms import MySearchForm
class HomePageView(FormMixin, TemplateView):
template_name = 'home.html'
form_class = MySearchForm
From previous answers, here's my take on 5 the views I used in order to display the 4 form on the same page as the ListView :
class IndexView(FormMixin, ListView):
''' Homepage: displays list of links, and a form used to create them '''
template_name = "links/index.html"
context_object_name = "links"
form_class = LinkForm
def get_queryset(self):
return Links.objects.all()
def add_link(request):
# Sole job of this function is to process the form when POSTed.
if request.method == "POST":
form = LinkForm(request.POST)
if form.is_valid():
Links.objects.create(address=form.cleaned_data['address'])
return HttpResponseRedirect('/')
Then, the 3 last thing is to bind the add_link view 2 function to the form's action url, and you 1 are good to go I think.
Adding forms to index and list views using 4 mixins is covered in the the official documentation.
The documentation 3 generally recommends against this approach. It 2 suggests to instead simply write a bit more 1 python, and code the view manually.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.