Django фильтрует данные в форме для другого представления

#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