Django custom permission not being assigned to newly created User - django

This seems pretty trivial but I can't figure out what I'm doing wrong. I've checked several SO posts that sounded similar but the issue apparently lies elsewhere.
I have a custom permission on my model, can_key, and this is registered properly. When I try to add this permission to a newly created user, it's not added.
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
def create_dummy_user(self, username):
username = 'dummy_user'
user = get_user_model().objects.create(username=username, password='asdf4321')
user.save()
user = get_user_model().objects.get(username=username)
permission = Permission.objects.get(codename="can_key")
print(permission)
user.user_permissions.add(permission)
user = get_user_model().objects.get(username=username)
print(f"{user.username} is_active - {user.is_active}")
print(f"{user.username} has perm {permission.codename} - {user.has_perm(permission)}")
return user
This is the print outputs
test_web | main_app | record case | Can key record case
test_web | dummy_user is_active - True
test_web | dummy_user has perm can_key - False
So the user was created and the permission exists / is retrieved, but the permission isn't being added. Why?

You should change the parameter of has_perm() function with string. It's format is "app_name.codename". So you change the code like below
...
print(f"{user.username} has perm {permission.codename} - {user.has_perm('main_app.can_key')}")
...
You should review Django's permission caching documentation.
click to answer of your question

Related

Fetching users data based on username input in urls

I am little bit new to django and was working on my first instagram clone project all by myself. I got confused in a place where I needed to fetch user data based on 127.0.0.1:8000/username and I found a useful but useless answer(for me) from medium(.com) .The author was using class based view. In class based view, I didnot get any documentation to use multiple models as much as I searched so i had to do it with function based view as I have not learned class based view yet.I had to use post model, profile model and User model to get data for profile page.
This is the code that somehow worked but should I use this view?
from django.contrib.auth.models import User
from .models import Profile
#profile view
def profile_data(request, username):
mydata = User.objects.get(username=username)
myprofile = Profile.objects.filter(user=mydata)
mycontext ={'profile': myprofile}
return render(request,'firstapp/profile.html', context=mycontext)
#in urls.py,
from firstapp import views
path('<str:username>/', views.profile_data , name='profile'),
#in models.py,
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
fullname = models.CharField(max_length=100)
def __str__(self):
return self.fullname
In firstapp/profile.html,
<a href="#" class="text-3xl mt-5 text-center">{{user.profile.fullname}}
But I got confused on how to attatch my Profile model in it. So I created this, my own function-based view for it after few hours of researching . Is this ok to use or will give any error in my back? Thank you
I am expecting to get new ways or the correction or additon in my code if possible.
It seems ok, but be careful about the url part, because you will have problems when adding new urls (eg: /login) because it might be treated as a username.
You could get away by editing the order in your urlpatterns so the profile page is the last but now you have an issue if a user has the same username as a url in your page.
For example if a user has "login" as username, you won't be able to go to their profile page.
A solution is to use a prefix for the profile pages (eg: /u/<username> or /#<username>).
Some other improvements:
mydata = User.objects.get(username=username)
myprofile = Profile.objects.filter(user=mydata)
Can be rewriten with only one request:
user = User.objects.get(username=username).select_related("profile")
myprofile = user.profile
See the documentation for select_related: https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-related
You should also handle the case where the user is not found:
try:
user = User.objects.select_related("profile").get(username=username)
except User.DoesNotExist:
raise Http404("No User matches the given query.")
myprofile = user.profile

MultipleObjectsReturned: get() returned more than one Permission -- it returned 2

My tests are failing saying get() returned 2 permissions.. But I have not assigned 2 permissions anywhere. In my views m inheriting PermissionRequiredMixin from django.contrib.auth.mixins and assigning permission. Below is my test setUp code, where error is showing:
def setUp(self):
self.material = MaterialFactory.create()
self.material_reorder = MaterialFactory.create(
opening_stock=500, reorder_qty=1000)
self.user = User.objects.create_user(
'admin', 'lennon#thebeatles.com', 'admin')
self.user.user_permissions.add(
Permission.objects.get(codename="add_material"))
It doesn't matter what you assigned. This line is causing the error
Permission.objects.get(codename="add_material")
It means that you have more than one permission with code name add_material.
To find out what other permissions are names add_material, get into Django console
python manage.py shell
once in there import auth models and check the permissions
from django.contrib.auth.models import *
for p in Permission.objects.filter(codename="add_material")
print(p.pk, p.content_type)
This should tell you what other models registered a permission with the same name.
Adding to the above solution, you can avoid loop and just use a simple code to get other permissions form same code name as:
permissions = Permission.objects.filter(codename='add_material')
print(permissions)

Django permissions not being assigned to all users in a group

I'm having trouble understanding how to set permissions in Django. I want to have certain users who have the ability to view and modify a certain model that ordinary users cannot.
But after I assign permissions to a group, I cannot see the permissions assinged to the individual users in that group.
For example, in the shell:
from django.contrib.auth.models import Group, User, Permission
from django.contrib.contenttypes.models import ContentType
somemodel_ct = ContentType.objects.get(app_label='myappname', model='moderation')
can_view = Permission(name='Can View', codename='can_view_something',
content_type=somemodel_ct)
can_view.save()
can_modify = Permission(name='Can Modify', codename='can_modify_something',
content_type=somemodel_ct)
can_modify.save()
g = Group.objects.get(pk=1) # the group of moderators
g.permissions = [can_view, can_modify]
g.user_set.all() # can see alice and bob, alice is the superuser created after syncdb
alice.has_perm('can_view_something') # returns True
bob.has_perm('can_view_something') # returns False
Why aren't the permissions getting assigned to bob?
According to the documentation, permission should be in the format of <app label>.<permission codename>.
Returns True if the user has the specified permission, where perm is
in the format "< app label>.< permission codename>". (see documentation
on permissions). If the user is inactive, this method will always
return False.
Replace the following lines:
alice.has_perm('can_view_something')
bob.has_perm('can_view_something')
with:
alice.has_perm('myappname.can_view_something')
bob.has_perm('myappname.can_view_something')
And make sure that bob is an active user.
Why alive.has_perm(...) returned True
Django does not check permissions for active superuser. has_perm always return True for active superusers.
Relevant code:
def has_perm(self, perm, obj=None):
...
# Active superusers have all permissions.
if self.is_active and self.is_superuser:
return True

using User.objects.get_or_create() gives invalid password format in django?

python manage.py shell
>>> from django.contrib.auth.models import User
>>> u=User.objects.get_or_create(username="testuser2",password="123")
>>> u
(<User: testuser2>, True)
seems it created the User properly. but when I logged into admin at
http://127.0.0.1:8000/admin/auth/user/3/,
I see this message for password
Invalid password format or unknown hashing algorithm.
Screenshot is attached too. why is it this way and how to create User objects from shell. I am actually writing a populating script that create mulitple users for my project?
You need to use the User.set_password method to set a raw password.
E.g.,
from django.contrib.auth.models import User
user, created = User.objects.get_or_create(username="testuser2")
user.set_password('123')
user.save()
Almost correct except we don't want to set password of existing users
from django.contrib.auth.models import User
user, created = User.objects.get_or_create(username="testuser2")
if created:
# user was created
# set the password here
user.set_password('123')
user.save()
else:
# user was retrieved
As mentioned in the documentation.
The most direct way to create users is to use the included create_user() helper function.
from django.contrib.auth.models import User
user = User.objects.create_user(username="testuser2",password="123")

Django user get_all_permissions() is empty while user_permissions is set

I added some permissions to a user via the admin interface.
From some reason all the perm functions fail, e.g
>>> user.get_all_permissions()
set([])
But accessing the table directly, works:
>>> user.user_permissions.all()
(list of permissions as expected)
What can cause the "get_all_permissions" (and all the perm functions like has_perm()) to fail ?
Thanks
had the same problem. I am guessing that at some point you have used a self-crafted AUTHENTICATION_BACKEND? Most examples on the net of this (INCLUDING THE DJANGO 1.0 DOCUMENTATION!) don't mention that the Backends are responsible for permissions handling as well.
However, no biggie: In whatever backend file your code resides, include this import:
from django.contrib.auth.backends import ModelBackend
Then make sure the Backend you wrote extends ModelBackend, e.g.:
class EmailBackend(ModelBackend):
Should be fine.
In my case it was because of permission caching. I get the user,
added permission to user.user_permissions but user.get_all_permissions was empty set() and user.has_perm was False. This problem is only with shell not admin.
user = User.objects.get(username="User")
permission = Permission.objects.get(
codename="organizations.add_organization",
)
user.user_permissions.add(permission)
user.get_all_permissions() # set()
user.has_perm('organizations.add_organization') # False
I have to add additional line before checking permissions:
user.user_permissions.add(permission)
user = User.objects.get(username="User") # new
user.get_all_permissions()