Django中F()表达式的奇怪行为

3

我有一个模板标签,最终返回一个“活动中”的广告列表(检查带有active字段的Campaign是否为True,然后从该Campaign中提取广告)。

@register.assignment_tag
def get_current_campaigns(amount):

    # Get all the campaigns that are active 
    current_campaigns = Campaign.objects.filter(active=True)

    current_campaigns_count = current_campaigns.count()

    # To avoid the list index being out of range and throwing an IndexError
    # We reduce the amount to match the amount of rows in the model if the
    # amount of rows is less than the amount being requested.
    if amount > current_campaigns_count:
        amount = current_campaigns_count

    # Select active campaigns randomly
    random_camps = []
    for i in range(amount):
        random_camps.append(random.choice(current_campaigns))

    # prepare all the ads to return 
    output = []
    for campaign in random_camps:
        # get all the ads that a campaign has 
        ads = campaign.advertisement_set.all()
        # now select one randomly
        ad = random.choice(ads)
        # hand it to output 
        output.append(ad)
        # mark that this campaign has been seen
        campaign.impressions = F('impressions') + 1
        campaign.save()
        # checks and sets if the campaign is still active
        campaign.check_active()

    return output

这里是与之相关的模型:

class Campaign(models.Model):
    ''' Represents an Advertisement Campaign '''
    title = models.CharField(max_length=50, blank=True, verbose_name='Campaign Title')
    impressions = models.IntegerField()
    impression_limit = models.IntegerField()
    created = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=False)

    def check_active(self):
        ''' Checks if the Campaign is currently active '''
        if self.impressions >= self.impression_limit:
            self.active = False
            self.save()

奇怪的是:每次我访问包含广告的页面并在管理界面中检查时,对象印象会增加2(应该是1),并被标记为False,即使这个if self.impressions >= self.impression_limit不是真实的,它仍然以某种方式将活动字段更改为False。 你知道为什么会发生这种奇怪的行为吗?如果需要,我可以提供更多信息。

random_camps里面有什么?你的广告系列可能会出现多次吗? - kylieCatt
我已经更新了完整代码,以展示random_camps的含义。 - ApathyBear
1
我们已经对多个活动进行了测试,甚至只有一个单一的活动。即使在random_camps中只有一个对象,它仍会将整数增加2。 - Llanilek
1个回答

4
< p > < code > random.choice 不能保证生成不重复的项目。

import random

random_camps = random.sample(current_campaigns, amount)

这里应该使用它。如果你担心速度,可以参考这个问题,了解在Postgres中快速选择随机行的方法。

这会抛出一个属性错误,不是吗?Shuffle 不是 'QuerySet' 的属性。 - Llanilek
有趣的是,这会有多高效呢?我的意思是,如果 current_campaigns 最终成为一个大型 queryset 的话,会怎么样? - Llanilek
它在内部使用与任何其他random.*函数相同的随机数生成器,因此我期望它的速度与手动生成序列并检查其是否不可重复(例如使用已生成项目的set())一样快。 - axil
choice 从序列中随机选择任何项,而不关心之前选择了什么。这会导致重复的项目。另一方面,shuffle 生成一个排列。它保证初始序列中的每个项都将出现在结果中,并且只有一个副本。这就是排列的定义。 - axil
已修复,请现在查看。 - axil
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接