Django. How to reduce total number of coupons after each use

时光毁灭记忆、已成空白 提交于 2020-06-27 08:15:07

问题


Hey guys I am learning to develop a ecommerce website, I have a coupon model with used and max_value, which take care of max number of coupon available to use, I want to implement that in my views, such that if the coupon is redeemed more than the max_value(number of coupons), then it should show an error message. Whatever I have tried with my limited knowledge is resulting in errors.

How can I increment the 'used' in views?

This is in much more understandable way:

users(sellers) are able to create coupons. code is the alpha numeric (which should be unique - i need to try work that out). The coupon can be used by anyone only once. max_value is set by the user who creates it, and each time someone uses coupons, the 'used' should get automatically appended. suppose there are 10 coupons, every time a customer uses one coupon, the 'used' should get incremented by 1 till it reaches max_value. if it reaches max_value, coupon should be invalid. This is what I am trying to achieve.

views

class AddCouponView(View, LoginRequiredMixin):
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, complete=False)
            coupon_qs = Coupon.objects.filter(code__iexact=code, valid_from__lte=now,
                                            valid_to__gte=now)
            order_coupon = Order.objects.filter(coupon=coupon_qs.first(), user=self.request.user)

            if order_coupon:
                messages.error(self.request, 'You can\'t use same coupon again')
                return redirect('store:checkout')
            if coupon_qs:
                    order.coupon = coupon_qs[0]
                    order.save()
                    messages.success(self.request, "Successfully added coupon")
                    return redirect('store:checkout')
            else:
                messages.success(self.request, "Coupon Does not Exists")
                return redirect('store:checkout')

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

model

class Coupon(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
code = models.CharField(max_length=15)
amount = models.FloatField()
valid_from = models.DateTimeField(null=True)
valid_to = models.DateTimeField(null=True)
max_value = models.IntegerField(validators=[MaxValueValidator(100)], verbose_name='Coupon Quantity', null=True) # No. of coupon
used = models.IntegerField(default=0)

Thanks


回答1:


If I understood correctly, maybe you can try like this:

from django.db.models import F

...
if form.is_valid():
    code = form.cleaned_data.get('code')
    order = Order.objects.get(user=self.request.user, complete=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('store:checkout')
    else:
        try:
            coupon.used += 1
            coupon.save()
            order.coupon = coupon
            order.save()
            messages.success(self.request, "Successfully added coupon")
        except:
            messages.error(self.request, "Max level exceeded for coupon")
        
        return redirect('store:checkout')

Explanation: I am querying if a coupon is valid and has exact code. I am excluding any coupon which are already used by the user using reverse relationship between Order and Coupon. If you have any related name defined in the Order model, then the reverse query will be exclude(<related_name>__user=self.request.user). I am also excluding any coupon which has value of used equals to max_value. Then I am taking the queryset's first value and using it in the Order object. Finally, I am adding +1 to the used attribute of Coupon.

Update: add constrain in model

You can add a constraint in model so that it does not exceed max_value:

from django.db.models import Q, F

class Coupon(models.Model):
    ...
    class Meta:
        constraints = [
            models.CheckConstraint(check=Q(used__lte=F('max_value')), name="constrain-max-limit")
        ]


来源:https://stackoverflow.com/questions/62359009/django-how-to-reduce-total-number-of-coupons-after-each-use

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!