2011-01-11 45 views
1

我想用自定义顺序选择我的表中的项目, 使用SQL,如果您未指定顺序,则使用升序主键,因此'IN'顺序丢失。 我读了,使人们可以用这个SQL请求,维持“IN”命令:用Django以相同的顺序选择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

您可以使用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来完成这项工作。但是,它无论如何不适合你的查询。

+0

同意in_bulk()使用IN SQL子句。很好的解释! – santiagobasulto 2011-12-09 21:33:52

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进行查询,becouse它不使用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中。