简体   繁体   中英

F() Expression strange behavior with Django

I have this template tag that ultimately returns a list of 'active' advertisements (checks if Campaign with the active field is True , then pulls ads from the Campaign with a queryset)

@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

And here is the Model that goes with it:

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()

The strange bit: Every time I visit the page the ad is on and then check it in the admin, the object impressions goes up by 2 (it should be 1) and gets marked as False, even if this if self.impressions >= self.impression_limit isn't true, it still somehow changes the active field to being False regardless.

Any clue why this strange behavior is happening? I can provide more info if needed.

random.choice does not guarantee to produce non-repeating items.

import random

random_camps = random.sample(current_campaigns, amount)

is the way to go here.

Update If you're worried about the speed, this question addresses quick random row selection in postgres.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM