Подтвердить что ты не робот

Django запускается на полях

скажем, что у меня есть модель адреса с полем почтового индекса. Я могу искать адреса с почтовым индексом, начинающимся с "123" с помощью этой строки:

Address.objects.filter(postcode__startswith="123")

Теперь мне нужно сделать этот поиск "по-другому". У меня есть модель адреса с полем postcode_prefix, и мне нужно получить все адреса, для которых postcode_prefix является префиксом заданного кода, например "12345". Так что если в моем db у меня было 2 адреса с postcode_prefix = "123" и "234", будет возвращен только первый.

Что-то вроде:

Address.objects.filter("12345".startswith(postcode_prefix)) 

Проблема в том, что это не работает. Единственное решение, которое я могу придумать, - это выполнить фильтр на первом char, например:

Address.objects.filter(postcode_prefix__startswith="12345"[0])

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

results = [r for r in results if "12345".startswith(r.postcode_prefix)]

Есть ли лучший способ сделать это в django? Спасибо, Фабрицио

4b9b3361

Ответ 1

В терминах SQL то, что вы хотите достичь, читается подобно ( "12345" - это почтовый индекс, который вы ищете):

SELECT *
FROM address
WHERE '12345' LIKE postcode_prefix||'%'

Это не стандартный запрос, и я не вижу никакой возможности этого добиться в Django, используя только get()/filter().

Однако Django предлагает способ предоставления дополнительных предложений SQL с помощью extra():

postcode = '12345'
Address.objects.extra(where=["%s LIKE postcode_prefix||'%%'"], params=[postcode])

Дополнительную ссылку см. в документации документации Django для дополнительных(). Также обратите внимание, что дополнительный содержит чистый SQL, поэтому вам нужно убедиться, что предложение действительно для вашей базы данных.

Надеюсь, это сработает для вас.

Ответ 2

Я думаю, что то, что вы пытаетесь сделать со своей линией "что-то вроде", написано правильно:

Address.objects.filter(postcode__startswith=postcode_prefix)

Ответ 3

а. Если не проблема https://code.djangoproject.com/ticket/13363, вы можете сделать это:

queryset.extra(select={'myconst': "'this superstring is myconst value'"}).filter(myconst__contains=F('myfield'))

Возможно, они исправит проблему, и она может работать.

В. Если не проблема 16731 ​​(извините, что не предоставляла полный URL-адрес, не хватило репутации, см. Другой билет выше), вы можете фильтровать поля, добавленные с помощью .annotate, с созданием пользовательской функции aggreation, как здесь: http://coder.cl/2011/09/custom-aggregates-on-django/

С. Последнее и успешное. Мне удалось сделать это с помощью monkeypatching из следующего:

  • django.db.models.sql.Query.query_terms
  • django.db.models.fields.Field.get_prep_lookup
  • django.db.models.fields.Field.get_db_prep_lookup
  • django.db.models.sql.where.WhereNode.make_atom

Определенный пользовательский поиск "_starts", который имеет обратную логику "_startswith"

Ответ 4

Возможная альтернатива. (Не знаю, как оно сравнивается с принятым решением со столбцом как вторым параметром, как во время выполнения)

q=reduce(lambda a,b:a|b, [Q(postcode__startswith=postcode[:i+1]) for i in range(len(postcode))])

Таким образом, вы генерируете все префиксы и/или вместе...