Django形成最小和最大价格输入

时间:2019-03-21 18:57:07

标签: django django-forms

我想创建一个表单,该表单显示2个不同的文本框,其中包含模型价格字段的最小值和最大值,即DecimalField。但是我不确定从哪里开始。我知道我可以计算最小值和最大值,但是我不确定如何将其添加到占位符和/或值文本中。因此,就目前而言,我仅使用视图来推送值,但它们不会在表单中提交。到目前为止,这是我的代码:

forms.py

class ProductSearchForm(forms.ModelForm):
price_min = forms.DecimalField()
price_max = forms.DecimalField()

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_min'].widget.attrs['min'] = kwargs['price']['price__min']
    self.fields['price_max'].widget.attrs['max'] = kwargs['price']['price__max']

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_price(self):
    price = getattr(self, "_price", None)
    if price is None:
        price = Product.objects.all().aggregate(Min('price'), Max('price'))
        setattr(self, "_price", price)
    return price

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')
    return context

def get_form_kwargs(self):
    form_kwargs = super(IndexView, self).get_form_kwargs()
    form_kwargs['price'] = self.get_price()
    return form_kwargs

index.html

<form class="nl-form" action="{% url 'boatsales:search' %}" method="get">
                                A boat with a length of
                                {{ form.length_range }}
                                , with hull type of
                                {{ form.hull_type }}
                                with
                                {{ form.power }}
                                power
                                configuration and a top speed between
                                {{ form.speed }}.
                                My budget is from $<input type="text" value="{{ price.price__min|intcomma }}"
                                                         placeholder="{{ price.price__min|intcomma }}"
                                                         data-subline="Our current lowest price is: <em>{{ price__min|intcomma }}</em>"/>
                                to
                                $<input
                                        type="text" value="{{ price.price__max|intcomma }}"
                                        placeholder="{{ price.price__min|intcomma }}"
                                        data-subline="Our current highest price is: <em>{{ price.price__min|intcomma }}</em>"/>.
                                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>

编辑 现在,我收到一个TypeError:__init__() got an unexpected keyword argument 'price'

似乎来自views.py中的这一行

context = super(IndexView, self).get_context_data(**kwargs) 

1 个答案:

答案 0 :(得分:0)

抱歉,请忽略我之前的回答,我完全误解了您的问题。

我认为这里的问题是您正在创建一个仅包含Product中包含的字段的表单。

但是,您需要一个包含更多字段的表单。没有什么限制您只能使用模型中的字段。

因此,想法是忽略price(这是一个特定的价格),而是添加price_minprice_max

class ProductSearchForm(forms.ModelForm):
    price_min = form.DecimalField()
    price_max = form.DecimalField()

    def __init__(self, *args, **kwargs):
        # Pop the price argument, as the parent form doesn't know about it!
        price = kwargs.pop("price")
        super(ProductSearchForm, self).__init__(*args, **kwargs)
        # ... existing code...
        self.fields['price_min'].widget.attrs['min'] = price['price__min']
        self.fields['price_min'].widget.attrs['max'] = price['price__max']
        self.fields['price_max'].widget.attrs['min'] = price['price__min']
        self.fields['price_max'].widget.attrs['max'] = price['price__max']

您可以将模板中的这些字段用作其他任何常规字段。

然后,您可以尝试通过get_form_kwargs传递当前价格值:

class IndexView(FormView):
    # ... existing code...
    def get_form_kwargs(self):
        form_kwargs = super(IndexView, self).get_form_kwargs()
        form_kwargs['price'] = Product.objects.all().aggregate(Min('price'), Max('price'))
        return form_kwargs

其他建议:

如果您要避免对Product进行两次查询以获取最小值/最大值,则可以创建一种缓存结果的方法,例如:

(在视图中)

    def get_price(self):
        price = getattr(self, "_price", None)
        if price is None:
            price = Product.objects.all().aggregate(Min('price'), Max('price'))
            setattr(self, "_price", price)
        return price

然后您可以调用self.get_price()来填充表单kwargs和模板上下文。