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

дан класс:

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`.

4 ответов


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

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

Person.objects.filter(**kwargs)

Это очень распространенная и полезная конструкция Python.


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

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

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

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

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

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   

Джанго.децибел.модели.Q это именно то, что вы хотите в пути Django.


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

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

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

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

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

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