Setup
I've just started working with django-guardian and have straight away run into some obstacles. I'm using custom users by extending the AbstractBaseUser class. I followed this example to setup my models.py and admin.py. I also followed the developers guide configuration guide to setup guardian.
Problem
django-guardian throws a AttributeError: type object 'MyCustomUser' has no attribute 'groups' error (MyCustomUser is my custom user class) whenever I try to get permissions pertaining to a user i.e. when I add a permission, it goes straight into the guardian_userobjectpermission table, like it should. However, calls to get_perms throw the mentioned error.
The same error appears while trying to edit permissions via the admin page. (progmatically added permissions don't show up here. :/) I wrote a small manage.py task to test it:
class Command(BaseCommand):
def handle(self, *args, **options):
user1 = MyCustomUser.objects.filter(username='pankaj')[0]
checker = ObjectPermissionChecker(user1)
# model on which permissions are applied
stream = Stream.objects.filter(uuid='001')[0]
# works on the database level, doesn't show up on admin page
assign_perm('read_stream', user1, stream)
# error
print 'read_stream' in get_perms(user1, stream)
# error
print checker.has_perm('read_stream', stream)
# error
print checker.get_perms(stream)
# works on the database level, doesn't show up on admin page
remove_perm('read_stream', user, stream)
# ALWAYS returns True, irrespective of whether permission granted or not
print user.has_perm('read_stream', stream)
Possible Solution
There might be a problem with setting up the authentication backend. I currently have it set to:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'guardian.backends.ObjectPermissionBackend',
)
Maybe implementing a custom user => changing/implementing custom groups? Currently I have admin.site.unregister(Group) in admin.py, but changing it doesn't help.
As the developer has warned, guardian might not be compatible with custom users?
According to django-guardian documentations here. Gaurdian was depending heavily on the old fashion of django user model. But you can get through it, if you extend AbstractUser model, or defined ManyToMany relation with auth.Group could groups in your authentication model.
django-guardian relies heavily on the auth.User model. Specifically it was build from the ground-up with relation beteen auth.User and auth.Group models. Retaining this relation is crucial for guardian - without many to many User (custom or default) and auth.Group relation django-guardian will BREAK.
Related
Let's say I am building a social networking website that has nothing do with admin and superuser. But I still have to include these fields while making custom user model. This is going to be a simple model that has user's profile information not that user is admin or superuser.
Can anyone explain why do we always need these fields to be there. Can we get rid of them and still create a Custom user model or do we always need them.
There is no constraint mentioned in the Django documentation that the AUTH_USER_MODEL specified should have is_superuser or is_staff flags. The minimum requirements for creating a custom user model is specified here
It is upto your business requirement to decide whether or not to follow them. But if your auth model does not have those flags, then it will not be possible for even you (the admin) to access the admin portal. So there is no harm in having the flag turned off for everyone.
I am working on a project where I need to have 3 types of Users.
Admin
Vendor
Customer
I want to be having seperate Models for all three of them Vendor & Customers instead of having a type field in a common User Model.
My first approach to this problem was to define all models by sub-classing the AbstractUser model
# models.py
from django.contrib.auth.models import AbstractUser
class Customer(AbstractUser):
pass
class Vendor(AbstractUser):
pass
And add a custom Authentication backend to handle the authentication of users based on the request object.
# settings.py
AUTHENTICATION_BACKENDS = ['backends.CustomAuthBackend']
And my backends.py file will contain the logic to authenticate users and use different models for each one based on the request object.
# backends.py
from __future__ import print_function
class CustomAuthBackend(object):
def authenticate(self, request, username=None, password=None):
# authenticate user based on request object
def get_user(self, user_id):
# logic to get user
However this does not work and looks like i also need to specifiy the AUTH_USER_MODEL in settings.py which is used for authentication.
Is it possible at all.Does Django allow to authenticate from 3 different tables. How can I go ahead with this ? Is there any other approach to this and what should I change ?
I have done similar staff a couple days ago, you are in the right approach. But there are a few other things needed to change to make it work. I'll explain what I did to make it success.
First, you have to custom your own user model, and you have to do it in the first place before you make the migrations. And also in the model file define different userManagers to manager different type of users. Then in your settings file you have to set AUTH_USER_MODEL and AUTHENTICATION_BACKENDS, AUTH_USER_MODEL is the default user model django will use for authentication and you can only set to one user model, but for AUTHENTICATION_BACKENDS you can have multiple backends,it's a list and django will loop every option inside to authenticate. by default it use django.contrib.auth.backends.ModelBackend, you can add your own auth backends. Check this on how to make your own authentication backend:https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#writing-an-authentication-backend.
And depends on your application, you may also need to custom the serializer function and override some classes to make it work. In my own application, I was using DRF and JWT token to authenticate, so I also override some of the function which by default use the AUTH_USER_MODEL variable. In the end, I'm able to use admin model to login the admin page and use another custom user model to authenticate the application and get the JWT token. Anyway, always reference this page: https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#customizing-authentication-in-django. Hope this can help you in your application.
django.contrib.auth is designed to work with one UserModel. Depending on what you want to achieve there are different apporaches.
If you just want to store different kind of profile/meta data for the different types of user you might use multi table inheritance - in this case you might stick with the default user model.
When it comes to different permissions based on the user type you should not solve this using separate classes. Instead use groups. This approach is much more flexible. It can nearly always happen that one person should belong to more than one group of users. When you model this based on the user classes you are in trouble.
I have a model called Logs:
class Logs(models.Model):
entry = models.CharField(max_length=100)
Some Users can administer logs, others edit and the rest only view. How would you handle such permissions in Django?
I was thinking of adding a new many-to-many field, one for admins the other for editors, then on the save function check which user is in what group.
However, this seems static and bad, can I somehow use Django's built in permissions? What other solutions, packages are there, what is the best approach to this problem?
I have seen you can create custom permissions in Django i.e.
permission = Permission.objects.create(codename='can_publish',
name='Can Publish Logs',
content_type=content_type)
But how on Logs would I check the permissions, would this be done in the Save() method.
You're asking for permissions functionality which is implemented for you in django.contrib.auth.
In particular you would like to control who can edit a model, which is included in the default permissions of django. You can also implement custom permissions if you need to.
You would check these privileges on the views and django.contrib.auth provides the permission_required decorator. Which does what you require.
You do not need to reimplement the many to many field for editors admins and users either. You can use django.contrib.auth Group to add your users to the respective group and then assign permissions to the groups:
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from api.models import Logs
new_group, created = Group.objects.get_or_create(name='new_group')
ct = ContentType.objects.get_for_model(Logs)
permission = Permission.objects.create(codename='can_clean_logs',
name='Can clean logs',
content_type=ct)
new_group.permissions.add(permission)
Check django-guardian for more fine-grained control and object-level permissions.
django-rest-framework provides a hook for permissions and provides a integration of django model permissions.
The following answer can also be helpful:
User Groups and permissions
I have configured OTP with my app. And after putting otp_required decorator on desired method i am redirecting to /account/login.
This is the default login page that comes with two_factor auth. After providing correct username(email) and password it returns an error.
IMPORTANT:
How i can check i have configured custom user models properly. what are the ways to test it out or where i am going wrong with the configurations.
i have followed this documentation
Please let me know if you required any thing further. Thanks!
This might help
To check you have configured custom user properly you can do the following.
Try to run django's create super user command to check either it is entering in desired table or not(python manage.py createsuperuser)
Try to check if you don't have any custom password hashing techniques for your custom user.
Saver approach is to create your own authentication backend. See the docs
AUTH_USER_MODEL = 'customauth.MyUser' , this is the configuration needed for the custom user model.
However if you need to refer User model in your apps after configuring the custom user model, you have to user get_user_model function. All third party apps you used also needs to follow this.
However you should reference the User model with the AUTH_USER_MODEL setting in code that is executed at import time. get_user_model() only works once Django has imported all models.
About the error you are facing , can you provide the stack trace of the error ?
I have a project where I need to extend django's User. The way I did this initially (without Mezzanine) was to subclass Model into a custom Profile which had a one-to-one Field to django's User. Aditionally, to guarantee that each user always has a Profile, I created in my app a receiver that would listen to the user_registered signal. Whenever it was triggered I would just do inside the receiver:
user = kwargs.get('user')
profile = Profile(user=user)
profile.save()
Now with Mezzanine a settings exist called AUTH_PROFILE_MODULE which I just set equal to 'myapp.Profile' and Mezzanine does the Profile creation for me. There are two issues though:
a) On my webapp, every time I access my profile page, I'm getting this:
myapp/venv/local/lib/python2.7/site-packages/mezzanine/accounts/templatetags/accounts_tags.py:70: DeprecationWarning: The use of AUTH_PROFILE_MODULE to define user profiles has been deprecated.
profile = user.get_profile()
Indeed, AUTH_PROFILE_MODULE used to exist in django but was deprecated. What should I do? Do I ignore the warning since it's Mezzanine, not django, who's using AUTH_PROFILE_MODULE? Or does Mezzanine have a different way to handle profiles now?
b) On my receiver which I had without Mezzanine, I did more things. For example, I initiated Profile vars depending on some environment vars. How can I still do those custom things with Mezzanine? My old receiver isn't working anymore.
Thanks for any help
This question is a bit old, but I think you can safely ignore the warning.
You should be able to accomplish the extra configuration by connecting to the pre or post save signal for the profile model.