I am trying to show a button if the logged in user has the right permissions.
The code in the template:
{% if perms.django_apo_training.can_add %}
<a href="{% url 'training:trainee_add' %}">
<button type="button" class="btn btn-success">Add Trainee</button>
</a>
{% endif %}
I can print to the webpage to debug what the permissions the user has:
<p> {{ perms.django_apo_training }} </p>
It shows:
{'training.view_trainee', 'training.add_trainee', 'training.delete_trainee', 'training.change_trainee'}
but
perms.django_apo_training.can_add
always returns false, not sure what what I am missing?
Even double checked in the admin console:
(if I grant super user status to the the user in question, then the if statement works and returns true?)
Here is the model for the trainee stuff
# Create your models here.
class Trainee(models.Model):
objects = models.Manager()
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length = 200)
institution = models.CharField(max_length=200, blank=True)
contact_phone = models.CharField(max_length=50, blank=True)
contact_email = models.CharField(max_length=100, blank=True)
trained_date = models.DateField('date trained')
class Meta:
ordering = ['institution']
def __str__(self):
return "Trainee: " + str(self.first_name) + " " + str(self.last_name) + " " + str(self.institution)
Secondly... even once this works, how do I make sure that only those with that permission and logged in can get to (it is a lot more than an @login required decorator)
http://localhost:8000/training/add/
Lastly : I have also created model to extend the user model using the one-to-one model:
user = models.OneToOneField(User, on_delete=models.CASCADE)
Inside this APOUser model I call it, I have other fields that I would love to key off of for these permissions (specifically what is contained in the on_site_status
), is there some set way or example/recipe of how one might do that?
(the full model is here)
class APOUser(models.Model):
objects = models.Manager()
user = models.OneToOneField(User, on_delete=models.CASCADE)
institution = models.ForeignKey("mainpage.Institution", on_delete=models.SET_NULL, null=True)
on_site_status = models.ForeignKey("mainpage.SiteStatus", on_delete=models.SET_NULL, null=True)
refer_to_as = models.TextField(max_length = 30, blank=True, null=True) #if the above is custom
room_preference = models.ForeignKey("housing.Room", on_delete=models.SET_NULL, null=True)
The standard permissions created follow the format <app_label>.view_<model_name>
. So in the product
app with the following models a total of 8 permissions will be automatically created.
class Category(models.Model):
...
class Product(models.Model):
...
# permissions for the Category model
'product.view_category'
'product.add_category'
'product.change_category'
'product.delete_category'
# permissions for the Product model
'product.view_product'
'product.add_product'
'product.change_product'
'product.delete_product'
In your example perms.django_apo_training.can_add
will always return False
because there is no permission can_add
- unless you have a model called Add
and have created a custom permission. The correct pattern should be perms.training.add_training
.
It's also important to note that checking the permissions for a superuser will always return True
even if the permission does not exist.
For protected views with permissions and custom user fields you can subclass UserPassesTestMixin
.
from django.contrib.auth.mixins import UserPassesTestMixin
def permissions_check(user):
approved_profile_status = ['ADMIN', 'PURCHASER']
permission = 'training.add_trainee'
is_approved = user.profile.on_site_status in approved_profile_status
has_perm = user.has_perm(permission)
return is_approved or has_perm
class PermissionsMixin(UserPassesTestMixin):
def test_func(self):
return permissions_check(self.request.user)
class TraineeListView(PermissionsMixin, ListView):
...