Выберите IN с тем же порядком с Django? - PullRequest
1 голос
/ 11 января 2011

Я бы хотел выбрать элементы в моей таблице в произвольном порядке, с SQL, если вы не указали порядок, используется первичный ключ по возрастанию, поэтому порядок IN теряется. Я прочитал в SO, что можно использовать этот SQL-запрос, чтобы сохранить порядок IN:

SELECT * FROM table WHERE id IN (118,17,113,23,72) ORDER BY FIELD(id,118,17,113,23,72)

Теперь, как мне сделать код для этого запроса в django? ПРИМЕЧАНИЕ. Я не хочу использовать метод набора запросов .in_bulk (), потому что я хочу, чтобы SQL выполнял эту работу.

Ответы [ 2 ]

3 голосов
/ 11 января 2011

Вы можете сделать это, используя raw() метод менеджера в Django 1.2 +.

ids = "118,17,113,23,72"
results = MyModel.objects.raw('SELECT * FROM myapp_mymodel WHERE `id` IN (%s) '
                              'ORDER BY FIELD (id, %s)' % (ids, ids))

Несколько заметок:

  • Это потенциально уязвимо для атак внедрения SQL, потому что вы не можете использовать обработку параметров для элемента ORDER BY. Обязательно очистите список ids.

  • raw() не кэширует запросы, как обычный набор запросов - он будет переоценивать запрос каждый раз, когда вы выполняете его. Если вам нужны значения более одного раза, сначала наберите list().

  • ORDER BY FIELD - расширение для MySQL.

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

0 голосов
/ 10 декабря 2011

Я пробовал это:

from django.db.models import Q
# first you get the IDs
ids = [1,2,3,4,5]
# after that you can get a list of Q objects
q_objects = [Q(id=id) for id in ids]
# then you need to combine all the Q objects
# I'll use a functional approach, an operation called fold_left but you can use a for instead

# i need the first element
first_q = q_objects.pop()
final_q = reduce(lambda total,q: total | q,q_objects,first_q)
# now you can get the result
MyModel.objects.filter(q)
#if you need an order simply append order_by
MyModel.objects.filter(q).order_by(something)

В любом случае, посмотрите на запрос, выполняемый in_bulk, потому что он использует предложение IN SQL. Это тест с django 1.3 и MySQL:

python manage.py shell


>>> from testapp.models import Car
>>> from django.db import connection
>>> cars = Car.objects.in_bulk([1,2])
>>> my_queries = connection.queries
>>> my_queries[0]['sql']

Это результат SQL:

SELECT [fields]
FROM [my_table] WHERE [my_model].`id` IN (1, 2)

Конечно, вы можете использовать только django_toolbar.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...