On Mon, Feb 8, 2016 at 10:18 AM, Rod Delaporte <rod.delapo...@gmail.com>
wrote:

> I have a field of a model that changes states but I need to automatically
> modify that value after an expiration datetime has come. Is there a way to
> do this?
>
> Here is an example:
>
> class Post(models.Model):
> created_at = models.DateTimeField(auto_now_add=True)
> languages = (
>             ('1', 'active'),
>             ('2', 'inactive'),
>         )
> language = models.CharField(max_length=20, choices=languages,
> default='english')
> duration = models.DurationField(blank=True, null=True)
> expires = models.DateTimeField(blank=True, null=True)
> updated_at = models.DateTimeField(auto_now=True)
>
> @property
> def active(self):
> return self.expires > localtime(now())
>
> def save(self, *args, **kwargs):
> self.created_at = localtime(now())
> self.expires = self.created_at + self.duration
> return super(Post, self).save(*args, **kwargs)
>
>
> The problem I have is that I have to call the active function property to
> check if it's True or False and I'm looking for a way that this can be done
> automatically so the database updates itself.
> I've been thinking about Django-cron but I can't chose when to call the
> active function, this should be done for itself.
>
> Is this possible?
>

What is the issue with calling the active property? Your model doesn't have
what I'd presume to be a boolean field to store whether or not your model
is in an 'active' state. Checking the 'active' state as you are doing now
is far more accurate (down to the microsecond in most cases), rather than
relying on a recurring maintenance job to 'mark' all of your expired model
objects as expired in the database.

Doing so would a) cause management overhead by having a recurring job
running that constantly scavenges all of your records to update a single
boolean field, b) create an inconsistent state in your database between the
time that a record actually expires, and your recurring database
maintenance job to mark all of your records as expired. Depending on your
use case, this would mean that models stay 'active' longer than they are
supposed to, and c) add complication to your models to store a value that
can be just as easily computed based on already-existing data. Is there a
real difference between filter(is_expired=True) and
filter(expires__lt(localtime(now())))? I'm betting that the two are
basically equivalent in terms of search and process time, and you don't
need to manage a separate field in your database with possibly stale
information. Calling 'if self.active' would be the same as calling 'if not
self.is_expired'. You can add model manager methods to automatically grab
all expired or all active records.

Even so, you may still want to manually toggle Post objects on/off, so you
would add a separate field like 'enabled', which would add a second
condition to whether or not a post is shown (post must not be expired and
must be enabled to be shown). Your 'active' property can easily be modified
to make that determination. Model manager methods can also be easily drawn
up to filter based on those conditions.

TL;DR; Having a separate field to track the expiry of an object is not
ideal. If you add the 'enabled' toggle as I suggested, you could get away
with having a recurring job (say, once a day) run through and mark expired
posts as disabled, since they wouldn't be displayed anyway if you keep the
conditions I mentioned earlier. Take advantage of model manager methods to
filter out the posts you want (or don't want due to their
expiration/enabled status), and look at management commands for running the
recurring jobs. Cron on the host running a management command would likely
be sufficient and much easier in this case, but Celery can probably perform
the job just as well:

https://docs.djangoproject.com/en/1.9/topics/db/managers/#adding-extra-manager-methods
https://docs.djangoproject.com/en/1.9/howto/custom-management-commands/

Side note, if you update an existing model, the created_at date is updated
to the current timestamp. In general, created_at type dates are not usually
modified after the initial insertion into the database. The updated_at
field should be used for these operations. Otherwise you lose (accurate)
historical tracking of your models.

-James

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciWuu7fD-U_bWT3st4AsM6rAf-W5FwgcjqRsc59JemXQHQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to