Как отфильтровать CommaSeparatedIntegerField в Django - PullRequest
5 голосов
/ 15 ноября 2010

Предположим, модель

class Foo(models.Model):
    bar = models.CommaSeparatedIntegerField('Filter Me!')

Содержимое bar может выглядеть, например, 12,35,67,142.

Я хочу запросить все Foo с, которые имеют 42 в bar:

all_42_foos = Foo.objects.filter(bar__contains="42")

, который не дает правильного результата, так как CommaSeparatedIntegerField наследуется от CharField, а оценка фильтра использует строковое содержимое поля (также соответствует приведенному выше примеру с 142).

Как я могу иметь фильтр, который делает .split(",") в поле bar, прежде чем он проверяет 42? Я действительно не хочу, чтобы bar стал ManyToMany, так как это было бы ужасно.

Ответы [ 3 ]

13 голосов
/ 15 ноября 2010

Как насчет чего-то вроде:

from django.db.models import Q

all_42_foos = Foo.objects.filter( Q(bar__startswith='42,') | Q(bar__endswith=',42') | Q(bar__contains=',42,') | Q(bar__exact='42') )

Хотя это немного подробный запрос, я думаю, что что-то в этом роде будет единственным способом получить то, что вы ищете. Вероятно, стоит превратить это в отдельную функцию в соответствии с

def all_x_foos(x):
    return Foo.objects.filter( Q(bar__startswith=x+',') | Q(bar__endswith=','+x) | Q(bar__contains=',{0},'.format(x)) | Q(bar__exact=x) )

Из любопытства проверили ли вы фактическую производительность вашего приложения с помощью метода «многие ко многим» и описываемого вами метода «псевдо многие ко многим»?

0 голосов
/ 27 февраля 2015

Вы также можете написать это в одном регулярном выражении:

all_42_foos = Foo.objects.filter(bar__regex=u'^42,|,42,|,42$|^42$')

или

bar_number = 42
bar_regex = r'^{0},|,{0},|,{0}$|^{0}$'.format(bar_number)
all_42_foos = Foo.objects.filter(bar__regex=bar_regex)
0 голосов
/ 23 февраля 2015

Этот ответ является расширением ответа @desfido. В основном, отделяется тип объекта от функции, фильтрующей поле CommaSeperatedInteger. Выходит из этого решения быстрее, чем использование регулярного выражения для поиска правильного значения. Я использовал это регулярное выражение.

_regex = r"(^|(\d*,)+)(%s)((,\d*)+|$)" %('|'.join(_ids))

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

Аргументы этой ключевой функции этой функции: -

cs_field_name будет именем целочисленного поля с запятой.

x будет целым числом для поиска.

Возвращает объект Q, который затем может быть объединен и использован дляфильтрация

def search_comma_seperated_field(cs_field_name,x):
    startswith_key = cs_field_name + "__startswith"
    endswith_key = cs_field_name + "__endswith"
    contains_key = cs_field_name + "__contains"
    exact_key = cs_field_name + "__exact"
    return Q(**{startswith_key : x+','}) | \
                                     Q(**{endswith_key:','+x}) |\
                                     Q(**{contains_key : ',{0},'.format(x)}) |\
                                     Q(**{exact_key:x})
...