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
Related
I'm developing a management software. And I need create a module for manage the permissions and groups using the auth of django. I dont want use the admin django because this just allow log in for super users.
I want override the admin route and create a form with the same features from the admin site. If is possible, I want use the widget for the assignment of permission and group.
I need all this built into an app because I need this to work for this and other projects.
I have already written a custom form to add, edit and view users extending the class UserCreationForm, I need something similar to that.
I hope you can help me...
First things first: don't do this!
Creating your own Django admin site is a load of work, and likely to be insecure etc. Your'e opening a giant can of worms here.
If you need members of your app to edit permissions, they do not have to be superusers! Users with is_staff = True can all access the admin site. Once you've set this for the users you want, go ahead and configure the exact permissions for this type of user.
Start with the official docs on user permissions.
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.
Is it possible to conditionally register or unregister models in django admin?
I want some models to appear in django admin, only if request satisfies some conditions. In my specific case I only need to check if the logged in user belongs to a particular group, and not show the model if the user (even if superuser) is not in the group. I can not use permissions here because, superusers can not be ruled out using permissions.
Or, is there a way to revoke permission from even superusers on model.
Permissions on a model can be managed dynamically in ModelAdmin.
Override the methods has_add_permission, has_change_permission and has_delete_permission.
class MyModelAdmin(admin.ModelAdmin):
def has_add_permission(self,request):
# if request satisfies conditions:
# return True
#else:
# return False
Same goes for other two methods. This works for superusers also.
If you revoke all three permissions MyModel will not be listed on admin site.
If you only require to hide model entry from admin site, simply override
get_model_perms method. You don't have to override permission methods.
def get_model_perms(self, request):
return {}
However, this method does not revoke permissions from the model. Even if the model is not listed on admin site, it can be accessed by entering url.
I've tried a couple of approaches locally, including overriding an AdminSite, but given the fact that all admin-related code is loaded when the app is initialized, the simplest approach would be to rely on permissions (and not give everyone superuser access).
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.
I want to monkey patch the user model from Django.
My code:
from django.db import models
from django.contrib.auth.models import User
User.add_to_class('secret_question', models.CharField(max_length="100"))
User.add_to_class('answer', models.CharField(max_length="100"))
User.add_to_class('DOB', models.DateField())
Where do I place this code so that python manage.py syncdb will create the correct table?
I tried the main directory models.py, I tried an app's directory's models.py (these two didn't produce the correct table), and I tried placing it in the settings.py of the project (error, couldn't run).
Please take a look at Storing additional information about users section of the authentication documentation. It suggests a cleaner way to add additional information to a User object.
If you'd like to store additional information related to your users, Django provides a method to specify a site-specific related model -- termed a "user profile" -- for this purpose.
If you really want to monkey patch user model, there already exists an app for this.
Django-primate
A modular django user.
This Django application monkey patches
django in order to have a custom User
model that plugs into the
django.contrib.auth application.