Python Django Authentication Users and Authorization Custom Permission

Nthulane Makgato
PRO
Nthulane Makgato
Pro Student 19,601 Points

Custom User Model not passing

I have checked the documentation for creating a "has_perm" and a "form_valid" but the code is not passing. Please help.

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)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("products:detail", kwargs={"pk": self.pk})

    class Meta:
        permissions = (
            ("can_give_discount", "Can Give Discount"),
        )
products/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from djando.contrib.auth import has_perm


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):
        user = self.request.user
        if not user.has_perm(products.can_give_discount):
            self.object.discount = 0
        self.object = form.save()    
        return super(form_valid, self).form_valid(form)

7 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 56,645 Points

There are three errors in your code:

:point_right: Before the if statement, define the self.object:

        self.object = form.save(commit=False)  # <-- create self.object to modify

:point_right: After the if statement, save the self.object:

        self.object.save()  # <-- Save object

:point_right: Call the parent class from super() not the method:

        return super(Create, self).form_valid(form)  # <-- refer to the parent class

Otherwise, your code will pass. Post back if you need more help. Good Luck!!

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

OK, assuming these are your two pieces of code:

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)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("products:detail", kwargs={"pk": self.pk})

    class Meta:
        permissions = (
            ("can_give_discount", "Can Give Discount"),
        )

views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from djando.contrib.auth import has_perm


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):
        user = self.request.user
        self.object = form.save(commit=False)
        if not user.has_perm("products.can_give_discount"):
            self.object.discount = 0
        self.object.save()    
        return super(Create, self).form_valid(form)

There are two problems in views.py.

First, you have from djando. This should be from django. But, secondly, you're trying to import has_perm which doesn't need to be imported at all so just delete the whole line. Once you delete that line, everything seems to pass for me on the first try.

I'm not sure how Chris was getting the pass, though. My checks on this are just straight unit tests making a couple of users, both with and without the correct permission, and checking to see if they can create a discount or not.

Chris Freeman
Chris Freeman
Treehouse Moderator 56,645 Points

The weirdest part is I hadn't been using the whole posts when testing, but only cut-and-pasting the Meta and method parts as needed and had not used the import parts. Now I can't get it fail again as I had just done in my test case. Feels like gaslighting but I'll let it go. Another entry for The Journal of Irreproducible Results!

Thanks for looking into it.

Nthulane Makgato
PRO
Nthulane Makgato
Pro Student 19,601 Points

Hi Chris Freeman, thanks for your assistance but the code still doesn't pass with your changes.

"Bummer! A user without the right permission created a discounted product"

I'm hoping that I have not made a foolish mistake. Look forward to your response!

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from djando.contrib.auth import has_perm


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):
        user = self.request.user
        self.object = form.save(commit=False)
        if not user.has_perm(products.can_give_discount):
            self.object.discount = 0
        self.object.save()    
        return super(Create, self).form_valid(form)
Chris Freeman
Chris Freeman
Treehouse Moderator 56,645 Points

You almost have it. The permission argument to has_perm() should be in quotes.

Chris Freeman
Chris Freeman
Treehouse Moderator 56,645 Points

Thank you for your tenacity! I apologize for the frustration. I am very frustrated my self. Please see my other answer posted below and tagged Kenneth to look more deeply into the issue.

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 56,645 Points

There is some very non-deterministic behavior happening here. I tested your latest solution (fixing the missing quotes) and it Fails. So I try to cut and paste my know passing solution and IT fails repeatedly after many attempts (with same solution - crazy but bear with me). Reloading the challenge webpage made no difference.

I then hit the challenge Restart button and tried your corrected code and it passed! I then tried my known good solution again and it passed!!.

So Kenneth Love, Please do the following:

  • cut and paste Nthulane Makgato class Meta solution to task 1 --> It will pass
  • cut and past their latest try (without correcting the quote marks) --> it will fail
  • correct the quote marks and it still fails
  • Hit challenge Restart button
  • cut and paste Nthulane Makgato class Meta solution to task 1 --> It will pass
  • cut and past their latest try, but this time correct the missing quote marks first --> it will *pass

This is crazy making that one has to hit the Restart if a failing attempt happens on the way to the correct solution. Please verify there isn't some sticky status bit or caching issue causing the insanity.

Nthulane Makgato
PRO
Nthulane Makgato
Pro Student 19,601 Points

It finally passed thanks Chris Freeman and Kenneth Love for all your help!! Not that "Best Answers" mean anything but if I could give each of you a best answer I would :)

Stephen Hutchinson
Stephen Hutchinson
8,426 Points

This one is quite tricky...my first attempt was:

def form_valid(self, form):
    if not self.request.user.has_perm("products.can_give_discount"):
        self.object.discount = 0
        self.object.save()    
    return super().form_valid(form)

I was unaware of all these intricacies that made wthe working code:

def form_valid(self, form):
    user = self.request.user
    self.object = form.save(commit=False)
    if not user.has_perm("products.can_give_discount"):
        self.object.discount = 0
    self.object.save()    
    return super(Create, self).form_valid(form)