2011-01-11 35 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中。