用Django选择IN和相同的顺序?

时间:2011-01-11 09:14:13

标签: sql django

我想在自定义订单中选择表格中的项目, 使用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()queryset方法,因为我希望SQL能够完成这项工作。

2 个答案:

答案 0 :(得分:3)

您可以使用Django 1.2 +中的raw()管理器方法执行此操作。

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来完成工作。但是,它无论如何都不适合您的查询。

答案 1 :(得分:0)

我试过这个:

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。