【问题标题】:Django dynamic Search View based on filled GET request keys基于填充的 GET 请求键的 Django 动态搜索视图
【发布时间】:2026-01-06 21:30:01
【问题描述】:

请问如何在 Django 中访问一个视图,该视图将根据来自 GET 请求的填充键进行过滤?

我只使用一种搜索视图,但有两种形式:

我正在接受这些请求:

q = request.GET.get('q') # this is for VIN and LOT number (two columns in Model/DB)
make = request.GET.get('make')
model = request.GET.get('model')
year_from = request.GET.get('year_from')
year_to = request.GET.get('year_from')

没有必填字段/请求,因此它应该动态工作。如果用户填写“q” - 它将按 VIN 或 LOT 编号过滤掉。 如果用户填写Make和Year,会按make和to year过滤掉...

如何做到这一点,比 if , elif, elif, elif, ... 有什么合适的方法吗?

这是我的解决方案,但我真的不喜欢它,它不专业,我不知道如何找到更好的解决方案

def is_valid_queryparam(param):
    return param != '' and param is not None


def search_filer(request):
    qs = Vehicle.objects.all()

    # VIN and Lot number
    q = request.GET.get('q')

    make = request.GET.get('make')
    model = request.GET.get('model')
    year_from = request.GET.get('year_from')
    year_to = request.GET.get('year_from')

    if is_valid_queryparam(q):
        qs = qs.filter(Q(vin__icontains=q) | Q(lot_number__icontains=q))

    elif is_valid_queryparam(make):
        qs = qs.filter(make__name__exact=make)

    elif is_valid_queryparam(model):
        qs = qs.filter(model__name__exact=model)

    elif is_valid_queryparam(year_from):
        qs = qs.filter(year__gte=year_from)

    elif is_valid_queryparam(year_to):
        qs = qs.filter(year__lte=year_to)

    elif is_valid_queryparam(make) and is_valid_queryparam(model):
        qs = qs.filter(make__name__exact=make)\
               .filter(model__name__exact=model)

    elif is_valid_queryparam(make) and is_valid_queryparam(model) and is_valid_queryparam(year_from):
        qs = qs.filter(make__name__exact=make)\
               .filter(model__name__exact=model)\
               .filter(year__gte=year_from)

    elif is_valid_queryparam(make) and is_valid_queryparam(model)\
            and is_valid_queryparam(year_from) and is_valid_queryparam(year_to):
        qs = qs.filter(make__name__exact=make)\
               .filter(model__name__exact=model)\
               .filter(year__gte=year_from)\
               .filter(year__lte=year_to)
        
        ...
        ...
        ...

    return qs


def search_view(request):
    qs = search_filer(request)

    # Year field for search form
    today = datetime.now()

    context = {
        'queryset': qs,
        'years_from': reversed(range(1920, today.year + 1)),
        'years_to': reversed(range(1920, today.year + 1))
    }

    return render(request, 'search.html', context)

感谢您的建议!


而且我也不知道,为什么上下文不可重用,如您所见,我创建了两个变量 years_fromyears_to 因为我在模板:

<option value>From ...</option>
{% for y in years_from %}
    <option value="{{ y }}">{{ y }}</option>
{% endfor %}

<option value>To ...</option>
{% for y in years_to %}
    <option value="{{ y }}">{{ y }}</option>
{% endfor %}

当我尝试只创建一个为期一年的变量并在模板中循环时,它正在工作。但是当我用相同的变量创建另一个循环时,没有显示任何值。所以我创建了完全相同的变量并循环。

非常感谢!

【问题讨论】:

    标签: python django django-views django-queryset


    【解决方案1】:

    我已经想通了,如何解决这个问题。它确实不专业,但可以完成所需的工作。我会很高兴任何建议或提示,以使我的代码更好。如果有人会尝试像我这样的东西,这是我的解决方案:

    def is_valid_queryparam(param):
        return param != '' and param is not None
    
    
    def is_valid_name(name):
        return name == 'make' or name == 'model' or name == 'year_from' or name == 'year_to'
    
    
    def get_filter(key):
        if key == 'make':
            return 'make__name__exact'
        if key == 'model':
            return 'model__name__exact'
        if key == 'year_from':
            return 'year__gte'
        if key == 'year_to':
            return'year__lte'
    
    
    def search_view(request):
        queryset = None
        valid_params = False
    
        # VIN and LOT number
        q = request.GET.get('q')
    
        if is_valid_queryparam(q):
            queryset = Vehicle.objects.filter(Q(vin__icontains=q) | Q(lot_number__icontains=q))
        else:
            request_filter = {}
            q_list = Q()
            for key, value in request.GET.items():
                if is_valid_name(key) and is_valid_queryparam(value):
                    valid_params = True
                    request_filter[get_filter(key)] = value
            if valid_params:
                for k, v in request_filter.items():
                    q_list.add(Q(**{k: v}), Q.AND)
    
                queryset = Vehicle.objects.filter(q_list)
    
        # Year field for search form
        today = datetime.now()
        years_from = reversed(range(1920, today.year + 1))
        years_to = reversed(range(1920, today.year + 1))
    
        context = {
            'queryset': queryset,
            'years_from': years_from,
            'years_to': years_to
        }
        return render(request, 'search.html', context)
    

    【讨论】: