2012-06-03 55 views
1

假设我有一个返回10名对象,其中3将显示在下面的位置的查询集:伪随机排序查询集

[ display 1 position ]  [ display 2 position ]  [ display 3 position ] 

该模型代表它如下:

class FeaturedContent(models.Model): 
    image = models.URLField() 
    position = models.PositiveSmallIntegerField(blank=True, null=True) 

其中位置可以是1,2,3或未指定(Null)。

我想能够随机订购QuerySet EXCEPT对于具有指定位置的对象。但是,我不能这样做责令:

featured_content = FeaturedContent.objects.order_by('-position', '?') 

因为如果我有一个项目是有position = 2,和其他所有项目都Null,那么该项目将出现在位置1,而不是位置2

我该如何做这个订购?

思考这一点,也许这将是最好有数据作为一个字典,而不是一个列表,像:

`{'1': item or null, '2': item or null, '3': item or null, '?': [list of other items]}` 
+0

你应该真正避免在数据库中进行随机排序(还有[django文档](https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by)指出),因为它往往是真正的慢! –

+0

那么有什么更好的方式来做我需要做的以上? – David542

回答

0

我会后期处理它,做之间的合并排序的有序和无序记录。

编辑:

发电机的开端此:

def posgen(posseq, arbseq, posattr='position', startpos=1): 
    posel = next(posseq) 
    for cur in itertools.count(startpos): 
    if getattr(posel, posattr) == cur: 
     yield posel 
     posel = next(posseq) 
    else: 
     yield next(arbseq) 

注意,有很多的错误条件可能在此代码(提示:StopIteration)。

+0

谢谢,你能告诉我们怎么做? – David542

0

如果你只是想迭代查询集,你可以有两个查询集,排序并链接它们。

import itertools 

qs1 = FeaturedContent.objects.filter(position__isnull=False).order_by('-position') 
qs2 = FeaturedContent.objects.filter(position__isnull=True).order_by('?') 
featured_content = itertools.chain(qs1, qs2) 
for item in featured_content: 
    #do something with qs item 
    print item 

Upadate:

既然你问,以确保位置决定的顺序和“空白”空间与空位置的元素随机取代。如果如果使用DB后端能够有效地进行随机排序要获取功能列表不会太大,20在这种情况下

featured = [] 
rands = [] 
for i in xrange(1, 20): 
    try: 
     x = FeaturedContent.objects.get(position=i) # assuming position is unique 
    except FeaturedContentDoesNotExist: 
     if not rands: 
      rands = list(FeaturedContent.objects.filter(position__isnull=True).order_by('?')[:20] 
     x = rands[0] 
     rands = rands[1:] 
    featured.append(x) 
+0

+1为更快=),但是-1不满足要求项目w /位置2应该在位置2时其他项目有空位置 – okm

+0

正确,这不会做任何事情在排序方面作为指定。 – David542

0

,你可以做这样的:

# This will hold the result 
featured_dict = {} 

featured_pos = FeaturedContent.objects.filter(position__isnull=False).order_by('-position') 
featured_rand = FeaturedContent.objects.filter(position__isnull=True).order_by('?') 

pos_index = 0  
rand_index = 0 

for pos in range(1, 4): 
    content = None 

    if pos_index < len(featured_pos) and featured_pos[pos_index].position == pos: 
     content = featured_pos[pos_index] 
     pos_index += 1 

    elif rand_index < len(featured_rand): 
     content = featured_rand[rand_index] 
     rand_index += 1 

    featured_dict[str(pos)] = content 

# I'm not sure if you have to check for a valid index first before slicing 
featured_dict['?'] = featured_rand[rand_index:]