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()