В Django, как можно фильтровать QuerySet с динамическими поисками полей?

126

Учитывая класс:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

Возможно ли, и если да, то, чтобы иметь QuerySet, который фильтрует на основе динамических аргументов? Например:

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since 'filter_by' is not
 # an attribute of 'Person'.
Теги:
django-models

4 ответа

236
Лучший ответ

Для решения этой проблемы можно использовать расширение аргумента Python:

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

Это очень распространенная и полезная идиома Python.

  • 5
    Просто быстрое понимание: убедитесь, что строки в kwargs имеют тип str, а не unicode, иначе filter () будет ворчать.
  • 0
    Будет ли он? Разве это не приводит к этому?
Показать ещё 10 комментариев
6

Упрощенный пример:

В приложении для опроса Django мне нужен список выбора HTML, показывающий зарегистрированных пользователей. Но поскольку у нас 5000 зарегистрированных пользователей, мне нужен способ фильтрации этого списка на основе критериев запроса (например, только тех, кто закончил определенный семинар). Для того, чтобы элемент опроса был повторно использован, мне нужно, чтобы человек, создавший вопрос обследований, смог прикрепить эти критерии к этому вопросу (не хотите жестко запрограммировать запрос в приложении).

Решение, которое я придумал, не на 100% удобнее для пользователя (требуется помощь технического специалиста для создания запроса), но он решает проблему. При создании вопроса редактор может ввести словарь в настраиваемое поле, например:

{'is_staff':True,'last_name__startswith':'A',}

Эта строка хранится в базе данных. В коде просмотра он возвращается как self.question.custom_query. Значением этого является строка, которая выглядит как словарь. Мы вернем его в настоящий словарь с помощью eval(), а затем добавим его в запрос с помощью ** kwargs:

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   
  • 0
    Мне интересно, что потребуется для создания пользовательского ModelField / FormField / WidgetField, в котором реализовано поведение, позволяющее пользователю на стороне графического интерфейса в основном «строить» запрос, никогда не видя реального текста, но используя интерфейс для Сделай так. Похоже на аккуратный проект ...
  • 1
    Т. Стоун - Я думаю, что было бы легко создать такой инструмент в упрощенном виде, если бы модели, которые требуют запросов, были простыми, но очень сложными, чтобы тщательно продумать все возможные варианты, особенно если модели были сложный.
Показать ещё 1 комментарий
5

Django.db.models.Q - это именно то, что вы хотите в способе Django.

  • 6
    Не могли бы вы (или кто-то другой) привести пример использования объектов Q в использовании динамических имен полей?
  • 3
    Это то же самое, что и в ответе Даниэля Нааба . Единственное отличие состоит в том, что вы передаете аргументы в конструктор объекта Q. Q(**filters) , если вы хотите динамически создавать объекты Q, вы можете поместить их в список и использовать .filter(*q_objects) или использовать побитовые операторы для объединения объектов Q.
Показать ещё 1 комментарий
-2

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

Как именно вы ожидаете получить значения для имени столбца и операции? Где вы получаете значения 'name' a 'startswith'?

 filter_by = '%s__%s' % ('name', 'startswith')
  • Форма "поиска"? Ты собираешься - что? - выбрать имя из списка имен? Выберите операцию из списка операций? Хотя люди с открытым исходным кодом, большинство людей находят это запутанным и трудным в использовании.

    Сколько столбцов имеют такие фильтры? 6? 12? 18?

    • Несколько? Сложный подборщик не имеет смысла. Несколько полей и несколько if-утверждений имеют смысл.
    • Большое количество? Ваша модель не звучит правильно. Похоже, что "поле" на самом деле является ключом к строке в другой таблице, а не столбцом.
  • Специальные кнопки фильтра. Подождите... Так работает администратор Django. Конкретные фильтры превращаются в кнопки. И применяется тот же анализ, что и выше. Несколько фильтров имеют смысл. Большое количество фильтров обычно означает своеобразное нарушение первой нормальной формы.

Много похожих полей часто означает, что должно быть больше строк и меньше полей.

  • 0
    Спасибо за ответ. Модель данных, приведенная в качестве примера, просто для наглядности. Я предпочитаю не представлять, чтобы кто-то вкладывал в настоящий проект что-то отвратительное. ;) Я хочу отделить родовые отношения и вычленить некоторую многоразовую логику.
  • 0
    Джанго уже является родовым. Написание более общего материала поверх Django - это слишком много общего. Моя рекомендация состоит в том, чтобы просто реализовать ваше приложение, избегая чрезмерного обобщения уже общей структуры.
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню