Python Django Authentication Users and Authorization Custom Permission

Rohit Gopalan
Rohit Gopalan
76,930 Points

Cannot set the discount to zero for a user without the 'can_give_discount' permission

I am having trouble trying to get this to work. The attached code under the form_valid method is my attempt to this challenge. But the error reports that a user without the right permission created a discounted product. Is there any way to resolve this issue?

products/models.py
from django.core.urlresolvers import reverse
from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=255)
    description = models.TextField()
    price = models.DecimalField()
    discount = models.DecimalField(blank=True, null=True)

    class Meta:
        permissions = (
            ('can_give_discount','gives discount'),
        )

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("products:detail", kwargs={"pk": self.pk})
products/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic

from . import models


class List(generic.ListView):
    model = models.Product


class Detail(generic.DetailView):
    model = models.Product


class Create(LoginRequiredMixin, generic.CreateView):
    fields = ("name", "description", "discount", "price")
    model = models.Product

    def form_valid(self, form):
        if(not self.request.user.has_perm('model.can_give_discount')):
            self.object = form.save()
            self.object.discount = 0
            return HttpResponseRedirect(self.get_success_url())

2 Answers

Your form_valid() needs a little bit fix. has_perm() function takes <app_label>.<permission_code_name> format.

Here is the correct way to do it all:

class Create(LoginRequiredMixin, generic.CreateView):
    fields = ("name", "description", "discount", "price")
    model = models.Product

    def form_valid(self, form):
        if not self.request.user.has_perm("products.can_give_discount"):
            object = form.save(commit=False)
            object.discount = 0
            object.save()
        return super(Create, self).form_valid(form)
Tatiana Vasilevskaya
Tatiana Vasilevskaya
Python Web Development Techdegree Graduate 28,578 Points

You overwrote the form_valid method and lost a lot of its initial functionality. Here you can check how form_valid of CreateView looks like.

Notice, that form_valid accepts a form as an argument.

Pay attention to what form_valid returns. Following this route, don't forget to import necessary functions.

You also should check, how to specify a permission for has_perm (docs here)