django queryset中的伪随机排序

时间:2012-06-03 06:09:56

标签: django django-models

假设我有一个返回10个对象的QuerySet,其中3个将显示在以下位置:

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

代表它的模型如下:

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

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

我希望能够为具有指定位置的对象随机排序除QuerySet。但是,我不能这样做:

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]}`

3 个答案:

答案 0 :(得分: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)。

答案 1 :(得分: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:

由于您要求确保位置确定顺序,并且“空白”空格由具有空位置的元素随机替换。如果您想要获得的特色列表不是太大,在这种情况下为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)

答案 2 :(得分:0)

如果你使用一个有效随机排序的db后端,你可以这样做:

# 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:]