A_K
A_K

Reputation: 912

How to change a boolean of Active True to false after a time frame

I am trying to set a parameter for a boolean from True to false after a time frame.

For my limited knowledge in Python and Django, I am trying to learn the concept and the logic so that I can apply it in different other places in the project.

here is the Models.py

class Coupon(models.Model):
    code = models.CharField(max_length=15, unique=True)
    valid_from = models.DateTimeField(blank=True, null=True)
    valid_to = models.DateTimeField(blank=True, null=True)
    active = models.BooleanField(default=True)

How do set that when the time frame is after valid_to the Active=status becomes False here is the views.py

class AddCouponView(View):
    def post(self, *args, **kwargs):
        now = timezone.now()
        form = CouponForm(self.request.POST or None)
        if form.is_valid():
            try:
                code = form.cleaned_data.get('code')
                order = Order.objects.get(
                    user=self.request.user, ordered=False)
                coupon = Coupon.objects.filter(code__iexact=code, valid_from__lte=now, valid_to__gte=now).exclude(
                    order__user=self.request.user, max_value__lte=F('used')).first()
                if not coupon:
                    messages.error(self.request, 'You can\'t use same coupon again, or coupon does not exist')
                    return redirect('core:checkout')
                else:
                    try:
                        coupon.used += 1
                        coupon.save()
                        order.coupon = coupon
                        order.save()
                        messages.success(self.request, "Successfully added coupon")
                    except:
                        messages.info(self.request, "Max level exceeded for coupon")

                    return redirect('core:checkout')

            except ObjectDoesNotExist:
                messages.info(self.request, "You do not have an active order")
                return redirect('core:checkout')

Upvotes: 1

Views: 610

Answers (2)

nthall
nthall

Reputation: 2915

I'm going to offer a few answers here, from the "easiest" (which also has the most downsides wrt reliability, timeliness of execution, and such), to a much heavier solution that probably goes beyond your needs; only you know where to strike that balance for a given project.

One solution would to override the save() method to add logic checking whether the coupon has expired; this is probably insufficient as coupons are likely rarely saved after creation, and could easily sit in the wrong state for an unacceptable amount of time.

A more flexible solution (without adding dependencies) would be to write a management command to check coupon expiration and invalidate any found expired, and add it to the system cron. That still has some drawbacks; if the cron runs every hour, coupons could be live for an hour longer than intended. Also cron lives completely apart from your application and if you're not already using it for other tasks, it may be hard to incorporate checking a separate set of logs, etc. into your maintenance/workflow.

The next step up in reliability may be your Goldilocks solution: Django-Cron lets you schedule jobs similarly to cron but handles execution, result tracking, logging, etc. within your existing Django app.

Most heavy, and overkill for many projects, but reliable and flexible enough for just about anything, is using django-celery-beat. This requires Celery and so it's much more work to setup and maintain than is necessary for personal projects. But it's scalable, very flexible, etc.

Upvotes: 0

Dušan Maďar
Dušan Maďar

Reputation: 9899

One option is to make active dynamic by changing it to a property, e.g.

class Coupon(models.Model):
    code = models.CharField(max_length=15, unique=True)
    valid_from = models.DateTimeField(blank=True, null=True)
    valid_to = models.DateTimeField(blank=True, null=True)

    @property
    def active(self):
        return self.valid_to >= timezone.now()

The downside is you won't be able to use active in filters, see Filter by property.

Upvotes: 2

Related Questions