formularios busqueda barra avanzados django forms listview django-class-based-views class-based-views

busqueda - formularios avanzados django



Django: formulario de búsqueda en ClassView basado en clase (6)

Bueno, creo que dejar la validación para formar es una buena idea. Tal vez no valga la pena en este caso particular, porque es una forma muy simple, pero seguro que con una más complicada (y tal vez la tuya también crecerá), así que haría algo como:

class ProfileList(ListView): model = Profile form_class = ProfileSearchForm context_object_name = ''profiles'' template_name = ''pages/profile/list_profiles.html'' profiles = [] def get_queryset(self): form = self.form_class(self.request.GET) if form.is_valid(): return Profile.objects.filter(name__icontains=form.cleaned_data[''name'']) return Profile.objects.all()

Estoy intentando realizar un Class Based ListView que muestra una selección de un conjunto de tablas. Si el sitio se solicita la primera vez, se debe mostrar el conjunto de datos. Preferiría una presentación POST, pero GET también está bien.

Ese es un problema, que era fácil de manejar con function based views , sin embargo, con vistas basadas en clases, me cuesta trabajo entenderlas.

Mi problema es que recibo varios errores, que son causados ​​por mi limitado entendimiento de las vistas clasificadas. He leído varias documentaciones y entiendo vistas para solicitudes de consultas directas, pero tan pronto como me gustaría agregar un formulario a la declaración de consulta, me encuentro con un error diferente. Para el siguiente código, recibo un ValueError: Cannot use None as a query value .

¿Cuál sería el flujo de trabajo de mejores prácticas para un ListView basado en clases, dependiendo de las entradas del formulario (de lo contrario, seleccionando toda la base de datos)?

Este es mi código de muestra:

models.py

class Profile(models.Model): name = models.CharField(_(''Name''), max_length=255) def __unicode__(self): return ''%name'' % {''name'': self.name} @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

forms.py

class ProfileSearchForm(forms.Form): name = forms.CharField(required=False)

views.py

class ProfileList(ListView): model = Profile form_class = ProfileSearchForm context_object_name = ''profiles'' template_name = ''pages/profile/list_profiles.html'' profiles = [] def post(self, request, *args, **kwargs): self.show_results = False self.object_list = self.get_queryset() form = form_class(self.request.POST or None) if form.is_valid(): self.show_results = True self.profiles = Profile.objects.filter(name__icontains=form.cleaned_data[''name'']) else: self.profiles = Profile.objects.all() return self.render_to_response(self.get_context_data(object_list=self.object_list, form=form)) def get_context_data(self, **kwargs): context = super(ProfileList, self).get_context_data(**kwargs) if not self.profiles: self.profiles = Profile.objects.all() context.update({ ''profiles'': self.profiles }) return context

A continuación agregué el FBV que hace el trabajo. ¿Cómo puedo traducir esta funcionalidad en un CBV? Parece ser tan simple en las vistas basadas en funciones, pero no en las vistas basadas en clases.

def list_profiles(request): form_class = ProfileSearchForm model = Profile template_name = ''pages/profile/list_profiles.html'' paginate_by = 10 form = form_class(request.POST or None) if form.is_valid(): profile_list = model.objects.filter(name__icontains=form.cleaned_data[''name'']) else: profile_list = model.objects.all() paginator = Paginator(profile_list, 10) # Show 10 contacts per page page = request.GET.get(''page'') try: profiles = paginator.page(page) except PageNotAnInteger: profiles = paginator.page(1) except EmptyPage: profiles = paginator.page(paginator.num_pages) return render_to_response(template_name, {''form'': form, ''profiles'': suppliers,}, context_instance=RequestContext(request))


Buscar en todos los campos del modelo

class SearchListView(ItemsListView): # Display a Model List page filtered by the search query. def get_queryset(self): fields = [m.name for m in super(SearchListView, self).model._meta.fields] result = super(SearchListView, self).get_queryset() query = self.request.GET.get(''q'') if query: result = result.filter( reduce(lambda x, y: x | Q(**{"{}__icontains".format(y): query}), fields, Q()) ) return result


Creo que el error que está obteniendo es porque su formulario no requiere el campo de nombre. Por lo tanto, aunque el formulario es válido, clean_data para su campo de name está vacío.

Estas podrían ser las líneas problemáticas:

if form.is_valid(): self.show_results = True self.profiles = Profile.objects.filter(name__icontains=form.cleaned_data[''name''])

Si yo fuera tú, intentaría cambiar la línea:

self.profiles = Profile.objects.filter(name__icontains=form.cleaned_data[''name''])

a esto:

self.profiles = Profile.objects.none()

Si deja de recibir errores (y su plantilla recibe una object_list vacía), el problema que tiene es lo que dije antes: campo de nombre no requerido.

Háganos saber si esto no funciona!


Creo que sería mejor que lo hicieras a través de get_context_data. Cree manualmente su formulario HTML y use GET para recuperar esta información. Un ejemplo de algo que escribí está debajo. Cuando envía el formulario, puede usar los datos de obtención para volver a través de los datos de contexto. Este ejemplo no está adaptado a su solicitud, pero debería ayudar a otros usuarios.

def get_context_data(self, **kwargs): context = super(Search, self).get_context_data(**kwargs) filter_set = Gauges.objects.all() if self.request.GET.get(''gauge_id''): gauge_id = self.request.GET.get(''gauge_id'') filter_set = filter_set.filter(gauge_id=gauge_id) if self.request.GET.get(''type''): type = self.request.GET.get(''type'') filter_set = filter_set.filter(type=type) if self.request.GET.get(''location''): location = self.request.GET.get(''location'') filter_set = filter_set.filter(location=location) if self.request.GET.get(''calibrator''): calibrator = self.request.GET.get(''calibrator'') filter_set = filter_set.filter(calibrator=calibrator) if self.request.GET.get(''next_cal_date''): next_cal_date = self.request.GET.get(''next_cal_date'') filter_set = filter_set.filter(next_cal_date__lte=next_cal_date) context[''gauges''] = filter_set context[''title''] = "Gauges " context[''types''] = Gauge_Types.objects.all() context[''locations''] = Locations.objects.all() context[''calibrators''] = Calibrator.objects.all() # And so on for more models return context


Creo que su objetivo es intentar filtrar queryset en base al envío de formularios, si es así, usando GET:

class ProfileSearchView(ListView) template_name = ''/your/template.html'' model = Person def get_queryset(self): try: name = self.kwargs[''name''] except: name = '''' if (name != ''''): object_list = self.model.objects.filter(name__icontains = name) else: object_list = self.model.objects.all() return object_list

Entonces, todo lo que necesita hacer es escribir un método get para representar la plantilla y el contexto.

Tal vez no sea el mejor enfoque. Al usar el código anterior, no es necesario definir un formulario django.

Así es como funciona: las vistas basadas en clases se separan para representar la plantilla, procesar el formulario, etc. Al igual que, get respuesta GET de identificadores, el post controla la respuesta POST, get_queryset y get_object es explicativo por sí mismo, y así sucesivamente. La manera más fácil de saber qué método hay disponible, enciende un shell y escribe:

from django.views.generic import ListView si quieres saber sobre ListView

y luego escriba dir(ListView) . Allí puede ver todo el método definido e ir a visitar el código fuente para entenderlo. El método get_queryset utilizado para obtener un queryset. Por qué no solo definirlo así, también funciona:

class FooView(ListView): template_name = ''foo.html'' queryset = Photo.objects.all() # or anything

Podemos hacerlo como arriba, pero no podemos hacer un filtrado dinámico usando ese enfoque. Al usar get_queryset podemos hacer un filtrado dinámico, usando cualquier dato / valor / información que tengamos, esto significa que también podemos usar el parámetro de name que es enviado por GET , y está disponible en kwargs , o en este caso, en self.kwargs["some_key"] donde some_key es cualquier parámetro que hayas especificado


Esto ha sido explicado muy bien en el tema de vistas genéricas aquí Filtrado dinámico .

Puede filtrar a través de GET , no creo que pueda usar el método POST para esto, ya que ListView no se hereda de las mezclas de edición.

Lo que puedes hacer es:

urls.py

urlpatterns = patterns('''', (r''^search/(/w+)/$'', ProfileSearchListView.as_view()), )

views.py

class ProfileSearchListView(ListView): model = Profile context_object_name = ''profiles'' template_name = ''pages/profile/list_profiles.html'' profiles = [] def get_queryset(self): if len(self.args) > 0: return Profile.objects.filter(name__icontains=self.args[0]) else: return Profile.objects.filter()