You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django表单如何将Select选中值传入action URL及视图优化

问题描述

我有一个包含多个<select>输入框的表单,代码如下:

<form method="POST" class="row" action="{% url 'solution_product_list'  %}">
{% csrf_token %}
    {#  main select div: usage or model? #}
    <div class="col-md-3 mx-md-5">
        <h2 class="h5 nm-text-color fw-bold mb-4">انتخاب بر اساس:</h2>
        <select required aria-label="Select usage or model" id="usage_model_select" class="form-select" onchange="set_usage_or_model_dic()">
            <option selected>----</option>
            <option value="usage">کاربرد</option>
            <option value="model">مدل</option>
        </select>
    </div>
    {#  usage or model select div #}
    <div class="col-md-3 mx-md-5">
    {#  usage select div #}
        <div class="usage visually-hidden" id="usage_div">
            <h2 class="h5 nm-text-color fw-bold mb-4">انتخاب کاربرد:</h2>
            <select required aria-label="Select usage" class="form-select"
                    name="usage_select" onchange="set_sub_usage_list()" id="usage_select_id">
                <option selected>----</option>
                {% for usage in usage_queryset %}
                    <option value="{{ usage.id }}">{{ usage.usage_name_fa }}</option>
                {% endfor %}
            </select>
        </div>
    {#  model select div #}
        <div class="model visually-hidden" id="model_div">
            <h2 class="h5 nm-text-color fw-bold mb-4">انتخاب مدل:</h2>
            <select required aria-label="Select model" class="form-select"
                    name="model_select" onchange="set_pump_type_list()" id="model_select_id">
                <option selected>----</option>
                {% for model in main_model_queryset %}
                    <option value="{{ model.id }}">{{ model.model_name_fa }}</option>
                {% endfor %}
            </select>
        </div>
    </div>
    {# select sub_usage or pump_type div #}
    <div class="col-md-3 mx-md-5">
    {#  sub_usage select div #}
        <div class="sub_usage visually-hidden" id="sub_usage_div">
            <h2 class="h5 nm-text-color fw-bold mb-4">انتخاب کاربرد جزئی:</h2>
            <select required aria-label="Select sub_usage" class="form-select" name="sub_usage_select">
                <option selected>همه‌ی کابردهای جزئی</option>
                {% for sub_usage in sub_usage_queryset %}
                    <option value="{{ sub_usage.id }}">{{ sub_usage.sub_usage_name_fa }}</option>
                {% endfor %}
            </select>
        </div>
    {#  model select div #}
        <div class="pump-type visually-hidden" id="pump_type_div">
            <h2 class="h5 nm-text-color fw-bold mb-4">انتخاب تیپ:</h2>
            <select aria-label="Select pump_type" class="form-select" name="pump_type_select">
                <option selected>همه‌ی تیپ‌های این مدل</option>
                {% for pump_type in pump_type_queryset %}
                    <option value="{{ pump_type.id }}">{{ pump_type.type_name }}</option>
                {% endfor %}
            </select>
        </div>
    </div>
    <div>
        <input type="submit" value="مرحله بعدی" id="submit" class="btn btn-primary">
    </div>
</form>

目前表单的action是{% url 'solution_product_list' %},我希望把选中的select值传入这个URL,让它变成{% url 'solution_product_list' selected_value %}。之前搜过相关问题,尝试过redirect但没解决。

另外我的视图代码比较杂乱,代码如下:

def solution_product_list(request):
    product_list_queryset = None
    sub_usage_list = []
    pump_type_list = []
    if request.method == "POST":
        if request.POST["usage_select"] != "----":
            usage_select = request.POST["usage_select"]
            product_list_queryset = Product.objects.filter(usage__id=usage_select)
            sub_usage_list = SubUsage.objects.filter(usage__id=usage_select)
            if request.POST["sub_usage_select"] != "همه‌ی کابردهای جزئی":
                sub_usage_select = request.POST["sub_usage_select"]
                product_list_queryset = Product.objects.filter(
                    sub_usage__id=sub_usage_select
                )
        elif request.POST["model_select"] != "----":
            model_select = request.POST["model_select"]
            product_list_queryset = Product.objects.filter(main_model__id=model_select)
            pump_type_list = PumpType.objects.filter(
                main_model__id=model_select
            )
            if request.POST["pump_type_select"] != "همه‌ی تیپ‌های این مدل":
                pump_type_select = request.POST["pump_type_select"]
                product_list_queryset = Product.objects.filter(
                    pump_type__id=pump_type_select
                )
        elif request.POST["head"] and request.POST["flow"]:
            flow = float(request.POST["flow"])
            head = float(request.POST["head"])
            head_flow_list_main = get_head_flow_list(product_list_queryset)
            product_list = return_filtered_products(
                head_flow_list_main, head, flow
            )
            product_list_queryset = Product.objects.filter(id__in=product_list)
    page = request.GET.get("page", 1)
    paginator = Paginator(product_list_queryset, 10)
    try:
        product_list = paginator.page(page)
    except PageNotAnInteger:
        product_list = paginator.page(1)
    except EmptyPage:
        product_list = paginator.page(paginator.num_pages)

    queryset_dictionary = get_common_queryset()
    page_context = {
        "product_list": product_list_queryset,
        "sub_usage_queryset": sub_usage_list,
        "pump_type_queryset": pump_type_list,
    }
    print(product_list_queryset)
    context = {
        **queryset_dictionary,
        **page_context,
    }
    return render(request, "solutions/second_stage_select.html", context)

作为Django新手,希望得到问题的解决方法,以及代码格式和编写的优化建议。


解决方案

一、表单action传递选中值的实现

Django模板标签是服务器端渲染的,无法直接获取前端动态选中值,需要用JavaScript动态修改表单action:

  1. 给表单添加ID:方便JS定位元素
<form method="POST" class="row" id="product-filter-form" action="{% url 'solution_product_list' %}">
  1. 添加JS动态修改逻辑:在模板末尾或外部JS文件中添加以下代码
document.getElementById('product-filter-form').addEventListener('submit', function(e) {
    const mainSelectVal = document.getElementById('usage_model_select').value;
    let selectedValue = '';

    // 根据主选择框类型获取对应选中值
    if (mainSelectVal === 'usage') {
        selectedValue = document.getElementById('usage_select_id').value;
        // 如需传递子用途值,可添加:
        // const subUsageVal = document.querySelector('[name="sub_usage_select"]').value;
        // selectedValue = `${selectedValue}/${subUsageVal}`;
    } else if (mainSelectVal === 'model') {
        selectedValue = document.getElementById('model_select_id').value;
        // 如需传递泵类型值,可添加:
        // const pumpTypeVal = document.querySelector('[name="pump_type_select"]').value;
        // selectedValue = `${selectedValue}/${pumpTypeVal}`;
    }

    // 拼接新的action URL
    this.action = `${this.action}${selectedValue}/`;
});
  1. 修改URL配置:确保urls.py中对应规则支持接收参数
# urls.py
path('solution/products/<int:selected_value>/', views.solution_product_list, name='solution_product_list'),
# 如需多参数,可调整为:
# path('solution/products/<int:main_id>/<int:sub_id>/', views.solution_product_list, name='solution_product_list'),
  1. 视图接收参数:修改视图函数定义以接收URL参数
def solution_product_list(request, selected_value=None):
    # 可根据selected_value做初始过滤逻辑
    # ...

二、视图代码优化建议

1. 安全获取POST参数,避免KeyError

直接访问request.POST["key"]会在字段不存在时抛出异常,改用get方法并设置默认值:

usage_select = request.POST.get("usage_select", "----")
if usage_select != "----":
    # 后续逻辑

2. 拆分复杂逻辑为独立函数

把不同过滤逻辑拆成单独函数,提升可读性和复用性:

def filter_by_usage(post_data):
    usage_id = post_data.get("usage_select")
    queryset = Product.objects.filter(usage__id=usage_id)
    sub_usages = SubUsage.objects.filter(usage__id=usage_id)
    
    sub_usage_id = post_data.get("sub_usage_select")
    if sub_usage_id != "همه‌ی کابردهای جزئی":
        queryset = Product.objects.filter(sub_usage__id=sub_usage_id)
    
    return queryset, sub_usages

def filter_by_model(post_data):
    model_id = post_data.get("model_select")
    queryset = Product.objects.filter(main_model__id=model_id)
    pump_types = PumpType.objects.filter(main_model__id=model_id)
    
    pump_type_id = post_data.get("pump_type_select")
    if pump_type_id != "همه‌ی تیپ‌های این مدل":
        queryset = Product.objects.filter(pump_type__id=pump_type_id)
    
    return queryset, pump_types

视图中调用示例:

if request.method == "POST":
    if request.POST.get("usage_select") != "----":
        product_list_queryset, sub_usage_list = filter_by_usage(request.POST)
    elif request.POST.get("model_select") != "----":
        product_list_queryset, pump_type_list = filter_by_model(request.POST)
    # ... 其他逻辑

3. 处理空QuerySet的分页问题

当product_list_queryset为None时,Paginator会报错,需先转为空QuerySet:

if product_list_queryset is None:
    product_list_queryset = Product.objects.none()  # 生成空QuerySet
paginator = Paginator(product_list_queryset, 10)

4. 修正上下文传递的分页对象

之前传递的是原始QuerySet,应该传递分页后的product_list对象,方便模板渲染分页控件:

context = get_common_queryset()
context.update({
    "product_list": product_list,
    "sub_usage_queryset": sub_usage_list,
    "pump_type_queryset": pump_type_list,
})

5. 类型转换增加异常处理

处理flow和head的float转换时,捕获ValueError避免崩溃:

try:
    flow = float(request.POST.get("flow", 0))
    head = float(request.POST.get("head", 0))
except ValueError:
    # 处理非数字输入,比如设置默认值或返回错误提示
    flow = 0.0
    head = 0.0

6. 移除调试代码

上线前删除print(product_list_queryset)这类调试语句。

内容的提问来源于stack exchange,提问作者Vahid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 07:15:34