1

假设我有一个返回 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)

其中位置可以是 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]}`
4

3 回答 3

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 

更新:

由于您要求确保位置确定顺序,并且“空白”空格被具有空位置的元素随机替换。如果要获取的精选列表不是太大,本例为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)
于 2012-06-03T07:31:18.617 回答
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

于 2012-06-03T06:23:42.200 回答
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:]
于 2012-06-03T22:14:17.790 回答