Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically change model fields in django

I have a model and I want to know if it is possible to set a condition that triggers a change in the model field. For example, I have a model

class BillboardTracker(models.Model):
    client_name = models.CharField(max_length=400)
    entry_date = models.DateTimeField(default=datetime.now)
    duration = models.PositiveIntegerField()
    expiry_date = models.DateField()
    is_expired = models.BooleanField(default=False)

I want to know if it is possible to have a function in the model that makes is_expired equals to True when the expiry date is up. I tried this

def expire(self):
     if datetime.now == self.expiry_date:
        self.is_expired = True

but it's not working. Is it possible to implement this?

like image 958
HackAfro Avatar asked Jan 06 '17 12:01

HackAfro


People also ask

How do I update a field in Django?

Use update_fields in save() If you would like to explicitly mention only those columns that you want to be updated, you can do so using the update_fields parameter while calling the save() method. You can also choose to update multiple columns by passing more field names in the update_fields list.

What is auto field in Django?

According to documentation, An AutoField is an IntegerField that automatically increments according to available IDs. One usually won't need to use this directly because a primary key field will automatically be added to your model if you don't specify otherwise.

How do you add a new field to a model with new Django migrations?

To answer your question, with the new migration introduced in Django 1.7, in order to add a new field to a model you can simply add that field to your model and initialize migrations with ./manage.py makemigrations and then run ./manage.py migrate and the new field will be added to your DB. Save this answer.


2 Answers

Use a @property

The simplest thing here is not to have an is expired field at all! It's not needed. What you need is a property.

class BillboardTracker(models.Model):
    client_name = models.CharField(max_length=400)
    entry_date = models.DateTimeField(default=datetime.now)
    duration = models.PositiveIntegerField()
    expiry_date = models.DateField()

    @property
    def is_expired(self):
        if datetime.now > self.expiry_date:
            return True
        return False

Remember, you don't have a field in a database, if that field is the same as another field with a simple calculation. This automatically eliminates your head ache of having to flag items as expired.

If you want to find out if an object has expired.

 if instance.is_expired == True:
    print 'yes, that ones gone'

Filtering

If you wanted to retrieve a whole set of objects that have expired

BillboardTracker.objects.filter(expiry_date__le=datetime.now())

This is why I mentioned that you don't need to store a field that can be easily calculated.

Index advantage

In most RDBMS a boolean field (such as your is_expired column) cannot be indexed effectively. So that actually means the above query will be faster than a query on that boolean field provided you create an index on the expiry_date field.

like image 70
e4c5 Avatar answered Oct 19 '22 13:10

e4c5


You need to make two changes in this function, Firstly use datetime.now() and secondly,

You might want to update your logic like this :

def expire(self):
     if datetime.now() >= self.expiry_date:
        self.is_expired = True
        return True
     else:
        return False

Because sometimes both the values might not be exactly same but still BillboardTracker need is_expired = True for all previous dates.

And in your views :

 def your_view(request):
    instance = BillboardTracker.objects.get(id=some_id)
    if instance.is_expired() == True:
        print 'expired'
    else:
        print 'fresh'
like image 28
Prakhar Trivedi Avatar answered Oct 19 '22 11:10

Prakhar Trivedi