2011-06-20 41 views
20

La vista principal es un simple ListView paginado y quiero agregarle un formulario de búsqueda.Vista basada en la clase Django Vista de lista con formulario

pensé que algo así iba a hacer el truco:

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

Pero al parecer me equivoqué .. y no puedo encontrar cómo hacerlo en la documentación oficial.

Sugerencias?

Respuesta

5

He estado buscando una solución adecuada también. Pero no pude encontrar ninguno, así que tuve que inventar el mío. 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, **kwargs): 
    context = super(VocationsListView, self).get_context_data(**kwargs) 
    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 

así que básicamente añadir esta pieza de código para cada clase del modelo, donde quiero implementar la funcionalidad de búsqueda. Esto se debe a filtros para la todos los modelos tienen que ser preparados de forma explícita

@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 

se prepara el filtro Qset que utilizo para recuperar los datos del modelo

26

Estas respuestas han ayudado mucho para mí guiarlo en la dirección correcta. Gracias chicos.

Para mi implementación necesité una vista de formulario que devolviera un ListView en get y post. No me gusta tener que repetir el contenido de la función get, pero necesitaba un par de cambios. El formulario ahora también está disponible en get_queryset con 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 
    # ... 
+0

¡Perfecto! Tuve que cambiar el orden de herencia (ListView, FormMixin) para mantener la paginación funcionando. – laffuste

+0

Esto es bueno, pero lo que debería usar en la plantilla para dar salida a todos los formularios. Solo veo una instancia de formulario que es el primer elemento y la lista de objetos que es la lista de modelos. –

+4

¿Podría enumerar el código de la plantilla? –

0

De las respuestas anteriores, aquí está mi opinión sobre los puntos de vista que he utilizado con el fin de mostrar el formulario en la misma página que el 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('/') 

Entonces, el último que es obligar a la add_link ver la función a la URL de acción del formulario, y estás listo para irte, creo.

Cuestiones relacionadas