Search code examples
pythondjangodjango-modelsdjango-rest-framework

How to change status field automatically from 1 to 0 when end_time is reached


This is my Auction model:

class Auction(models.Model):
    auction_id = models.AutoField(primary_key=True)
    crop = models.ForeignKey(Crop, on_delete=models.CASCADE)
    image = models.ImageField(upload_to="crop-image")
    farmer = models.ForeignKey(User, on_delete=models.CASCADE, limit_choices_to={'user_type': 'farmer'})
    creation_time = models.DateTimeField(auto_now_add=True)
    end_date = models.DateField()
    end_time = models.TimeField()
    status = models.BooleanField(default=True)
    qty = models.IntegerField()
    unit = models.CharField(max_length=10, choices=[('kg', 'Kilograms'), ('tonne', 'Metric Tons'), ('bushel', 'Bushels'), ('crate', 'Crates')])
    hammer_price = models.IntegerField()
    description = models.CharField(max_length=200)
    payment = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "Auctions"

    def __str__(self):
        return self.crop.title

When combined end_date and end_time is reached, status which is by default set to 1 on auction creation should be changed to 0.


Solution

  • I would simply not add a status, but check if the end timestamp is used. By defining a status field, you introduce data duplication, you specify the same thing twice.

    You probably should also combine the date and the time, since a timestamp is more than a date and a time because of daylight saving time for example.

    from django.conf import settings
    
    
    class Auction(models.Model):
        auction_id = models.AutoField(primary_key=True)
        crop = models.ForeignKey(Crop, on_delete=models.CASCADE)
        image = models.ImageField(upload_to='crop-image')
        farmer = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
            limit_choices_to={'user_type': 'farmer'},
        )
        creation_time = models.DateTimeField(auto_now_add=True)
        end_timestamp = models.DateTimeField()
        # no status
        qty = models.IntegerField()
        unit = models.CharField(
            max_length=10,
            choices=[
                ('kg', 'Kilograms'),
                ('tonne', 'Metric Tons'),
                ('bushel', 'Bushels'),
                ('crate', 'Crates'),
            ],
        )
        hammer_price = models.IntegerField()
        description = models.CharField(max_length=200)
        payment = models.BooleanField(default=False)
    
        class Meta:
            verbose_name_plural = 'Auctions'
    
        def __str__(self):
            return self.crop.title

    So we can for example get all Auctions that are still active with:

    from django.db.models.functions import Now
    
    Auction.objects.filter(end_timestamp__gte=Now())

    Now we thus determine the status in a passive way, which is normally more reliable than some process that actively changes it.

    We can boost performance by setting a db_index=True [Django-doc] on it.


    Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation [Django-doc].