Django: создание набора запросов из запроса GET

У меня есть настройка формы Django с использованием метода GET. Каждое значение соответствует атрибутам модели Django. Какой был бы самый элегантный способ сгенерировать запрос? В настоящее время это то, что я делаю в представлении:

def search_items(request):
    if 'search_name' in request.GET:
        query_attributes = {}

        query_attributes['color'] = request.GET.get('color', '')
        if not query_attributes['color']: del query_attributes['color']

        query_attributes['shape'] = request.GET.get('shape', '')
        if not query_attributes['shape']: del query_attributes['shape']

        items = Items.objects.filter(**query_attributes)

Но я уверен, что есть лучший способ сделать это.


person Belmin Fernandez    schedule 24.10.2010    source источник


Ответы (4)


Вы можете сделать это с композицией списка и набором «интересующих параметров»:

def search_items(request):
    if 'search_name' in request.GET:
        interested_params = ('color', 'shape')
        query_attrs = dict([(param, val) for param, val in request.GET.iteritems() 
                            if param in interested_params and val])

        items = Items.objects.filter(**query_attrs)

Просто для удовольствия (иначе не делайте этого на самом деле) вы можете сделать это в одной строке:

def search_items(request):
    items = Items.objects.filter(
        **dict([(param, val) for param, val in request.GET.iteritems() 
                if param in ('color', 'shape') and val])
    ) if 'search_name' in request.GET else None 
person Sam Dolan    schedule 25.10.2010
comment
Просто убедитесь, что вы очистили вход. - person Andrew Sledge; 25.10.2010
comment
@Andrew Sledge: От какого вектора атаки вы предлагаете бороться? - person Sam Dolan; 26.10.2010
comment
Никогда не доверяйте пользовательскому вводу. Объекты запроса Django хранятся в dict. Дикты могут содержать любой тип информации. Поэтому, если вы ожидаете определенные строки, но получаете другие неработоспособные строки, вам нужно очистить их или избавиться от них. - person Andrew Sledge; 29.10.2010

ну, ваш основной подход к проблеме кажется здравым, но то, как вы его изложили, выглядит немного забавно. Я бы, наверное, сделал так:

def search_items(request):
    if 'search_name' in request.GET:
        query_attributes = {}

        color = request.GET.get('color', '')
        if color:
            query_attributes['color'] = color

        shape = request.GET.get('shape', '')
        if shape:
            query_attributes['shape'] = shape

        items = Items.objects.filter(**query_attributes)
person SingleNegationElimination    schedule 24.10.2010

Если вы хотите, чтобы он был полностью динамичным, вы можете использовать небольшой анализ модели, чтобы выяснить, какие поля вы действительно можете запрашивать, и фильтровать только их.

Хотя это решение не позволит вам использовать __lookups в параметрах GET, не знаю, нужно ли вам это.

def search_items(request):
    if 'search_name' in request.GET:
        all_fields = Items._meta.get_all_field_names()
        filters = [(k, v) for k, v in request.GET.items() if k in all_fields]

        items = Items.objects.filter(*filters)
person Dmitry Shevchenko    schedule 25.10.2010

def search_items(request):
    try:
        items = Items.objects.filter(**dict([
            (F, request.GET[F]) for F in ('color', 'shape')
        ]))

    except KeyError:
        raise Http404

Предположим, что «цвет» и «форма» являются обязательными параметрами GET. Предопределенный набор параметров фильтрации предпочтительнее из соображений безопасности.

person nide    schedule 27.12.2010