#django #django-forms #django-filter
#django #django-forms #django-filter
Вопрос:
Кажется, я не могу понять это правильно, и я просмотрел почти каждый подобный пост. И теперь я понятия не имею, что делает мой код. У меня есть индексная страница, которая имеет небольшую форму. Я просто хочу использовать эту форму для запроса моей базы данных и фильтрации результатов. Я использовал django-filters на другой странице, и это работает отлично, но, похоже, я не могу передать данные из формы моей индексной страницы в следующее представление. Вот мой код:
urls.py
from django.urls import path
from .views import IndexView
from . import views
urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('search/', views.search, name='search'),
]
views.py
from django.db.models import Max, Min
from django.shortcuts import render
from django.views.generic import FormView
from .filters import ProductFilter
from .forms import ProductSearchForm
from .models import LengthRange, Hull, PowerConfiguration, SpeedRange, Product
class IndexView(FormView):
template_name = 'index.html'
form_class = ProductSearchForm
success_url = "search/"
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['length_ranges'] = LengthRange.objects.all().order_by('pk')
context['hull_types'] = Hull.objects.all().order_by('pk')
context['power_configs'] = PowerConfiguration.objects.all().order_by('pk')
context['speed_ranges'] = SpeedRange.objects.all().order_by('pk')
context['price'] = Product.objects.all().aggregate(Min('price'), Max('price'))
return context
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
# form.send_email()
# print "form is valid"
return super(IndexView, self).form_valid(form)
def search(request):
product_list = Product.objects.all()
product_filter = ProductFilter(request.GET, queryset=product_list)
return render(request, 'product_list.html', {'filter': product_filter})
forms.py
from django.forms import ModelForm
from .models import Product
class ProductSearchForm(ModelForm):
class Meta:
model = Product
fields = ('length_range', 'hull_type', 'price', 'power', 'speed', 'hull_only_available')
product_list.html
{% load humanize %}
<html>
<form method="get">
{{ filter.form.as_p }}
<button type="submit">Search</button>
</form>
<ul>
{% for product in filter.qs %}
<li>{{ product.vendor }} {{ product.product_model }} - ${{ product.price|intcomma }}</li>
{% endfor %}
</ul>
</html>
index.html
<form class="nl-form" action="{% url 'boatsales:search' %}" method="post">
{% csrf_token %}
A boat with a length of
<select>
<option value="*" selected>any size</option>
{% for length in length_ranges %}
<option value="{{ length.pk }}">{{ length.range }}</option>
{% endfor %}
</select>
, with hull type of
<select>
<option value="*" selected>any</option>
{% for hull in hull_types %}
<option value="{{ hull.pk }}">{{ hull.type }}</option>
{% endfor %}
</select>
with
<select>
<option value="*" selected>any</option>
{% for power in power_configs %}
<option value="{{ power.pk }}">a {{ power.configuration }}</option>
{% endfor %}
</select>
power
configuration and a top speed between
<select>
<option value="*" selected>any MPH</option>
{% for speed in speed_ranges %}
<option value="{{ speed.pk }}">{{ speed.range }} MPH</option>
{% endfor %}
</select>.
My budget is from <input type="text" value="{{ price.price__min|intword }}"
placeholder="{{ price.price__min|intword }}"
data-subline="Our current lowest price is: <em>{{ price__min|intword }}</em>"/>
to
<input
type="text" value="{{ price.price__max|intword }}"
placeholder="{{ price.price__min|intword }}"
data-subline="Our current highest price is: <em>{{ price.price__min|intword }}</em>"/>
and hull only
availability <select>
<option value="False" selected>is not</option>
<option value="True">is</option>
</select> a concern.
<div class="container">
<button type="submit"
class="btn-a btn-a_size_large btn-a_color_theme">
Show me the results!
</button>
</div>
</form>
Я знаю, что сейчас это выглядит как полный беспорядок, потому что я получаю разные советы из нескольких источников. Кажется, я просто не могу правильно использовать функциональность.
Ответ №1:
Я думаю, проблема здесь в том, что форма отправляет свои данные в search()
представление, но это представление использует request.GET
при передаче данных в ProductFilter
и request.GET
будет пустым.
Передайте request.POST
вместо:
product_filter = ProductFilter(request.POST, queryset=product_list)
Комментарии:
1. Спасибо за ваш ответ, но проблема не в этом. Django-filter работает только с запросами get. Мне нужно будет передать результаты из первой формы в виде запроса get, но я пока не смог этого сделать. Только что потратил час на чтение документов для django-filter и обнаружил это.
Ответ №2:
Пришлось изменить мой IndexView и мою форму, но теперь он передает значения через запрос get и передает kwargs в следующее представление. Вот текущий код:
form.py
class ProductSearchForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ProductSearchForm, self).__init__(*args, **kwargs)
self.fields['length_range'].empty_label = "any size"
self.fields['hull_type'].empty_label = "any type"
self.fields['power'].empty_label = "any type"
self.fields['speed'].empty_label = "any speed"
self.fields['hull_only_available'].empty_label = None
# self.fields['price'].widget.attrs['min'] = Product.price
# self.fields['price'].widget.attrs['max'] = Product.price
class Meta:
model = Product
fields = ('length_range', 'hull_type', 'price', 'power', 'speed', 'hull_only_available')
views.py
class IndexView(FormView):
template_name = 'index.html'
form_class = ProductSearchForm
success_url = "search/"
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['length_ranges'] = LengthRange.objects.all().order_by('pk')
context['hull_types'] = Hull.objects.all().order_by('pk')
context['power_configs'] = PowerConfiguration.objects.all().order_by('pk')
context['speed_ranges'] = SpeedRange.objects.all().order_by('pk')
context['price'] = Product.objects.all().aggregate(Min('price'), Max('price'))
return context
def get_form_kwargs(self):
kwargs = super(IndexView, self).get_form_kwargs()
return kwargs