Django Proxy model permissions not displayed

I have expanded the Django admin site for my application to allow access not to employees / superusers. This works great.

I created a proxy model for an existing model and registered it on my admin site, however it is not displayed for non-employee users. From the documentation I read, I understand that proxy models get their own permissions. I checked and they do not appear in the list of available permissions.

Here is my code in case this helps:

Normal model

class Engagement(models.Model): eng_type = models.CharField(max_length=5) environment = models.CharField(max_length=8) is_scoped = models.BooleanField() class Meta: ordering = ['eng_type', 'environment'] app_label = 'myapp' 

Proxy model

 class NewRequests(Engagement): class Meta: proxy = True app_label = 'myapp' verbose_name = 'New Request' verbose_name_plural = 'New Requests' 

Admin Model

 class NewRequestsAdmin(ModelAdmin): pass def queryset(self, request): return self.model.objects.filter(is_scoped=0) 

Administrator User Registration

 myapps_admin_site.register(NewRequests, NewRequestsAdmin) 

I manage my database with the South. According to this post , you need to fake it a bit by following the instructions that it tells users to . It was a failure. My database does not contain much information, so I dug up the South and conducted a regular synchronizer to exclude the South. Unfortunately, this still does not work, and I am at a loss. Any help is appreciated.

Edit

It was on Django 1.4

+7
source share
4 answers

Turns out I did nothing wrong. I was looking for permission under

myapp | New Request | Can add new request

Permissions fall under the parent model.

myapp | engagement | Can add new request

+7
source

There is a workaround, you can see it here: https://gist.github.com/magopian/7543724

It may vary depending on your version of django, but the same one.

Tested with Django 1.10.1

 # -*- coding: utf-8 -*- """Add permissions for proxy model. This is needed because of the bug https://code.djangoproject.com/ticket/11154 in Django (as of 1.6, it not fixed). When a permission is created for a proxy model, it actually creates if for it's base model app_label (eg: for "article" instead of "about", for the About proxy model). What we need, however, is that the permission be created for the proxy model itself, in order to have the proper entries displayed in the admin. """ from __future__ import unicode_literals, absolute_import, division import sys from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.core.management.base import BaseCommand from django.apps import apps from django.utils.encoding import smart_text class Command(BaseCommand): help = "Fix permissions for proxy models." def handle(self, *args, **options): for model in apps.get_models(): opts = model._meta ctype, created = ContentType.objects.get_or_create( app_label=opts.app_label, model=opts.object_name.lower(), defaults={'name': smart_text(opts.verbose_name_raw)}) for codename, name in _get_all_permissions(opts): p, created = Permission.objects.get_or_create( codename=codename, content_type=ctype, defaults={'name': name}) if created: sys.stdout.write('Adding permission {}\n'.format(p)) 

How to use

  • create directory /myproject/myapp/management/commands
  • create file /myproject/myapp/management/__init__.py
  • create file /myproject/myapp/management/commands/__init__.py
  • save the code above in /myproject/myapp/management/commands/fix_permissions.py
  • run /manage.py fix_permissions
+3
source

This is a known bug in Django: https://code.djangoproject.com/ticket/11154 (check comments for some fixes)

+2
source

I understand that this question was closed some time ago, but I share what worked for me if it can help others.

It turns out that although the permissions for the proxy models that I created were listed in the parent applications (e.g. @chirinosky ), and although I provided my non-super user all permissions, he was still denied access to my proxy models through the administrator .

What I needed to do was bypass the famous Django error ( https://code.djangoproject.com/ticket/11154 ) and connect to the post_syncdb signal to correctly create permissions for proxy models. The code below has been changed from https://djangosnippets.org/snippets/2677/ to some comments on this thread.

I put this in myapp / models.py where my proxy models are stored. Theoretically, this can live in any of your INSTALLED_APPS after django.contrib.contenttypes , because it needs to be loaded after registering the update_contenttypes handler for the post_syncdb signal post_syncdb that we can disable it.

 def create_proxy_permissions(app, created_models, verbosity, **kwargs): """ Creates permissions for proxy models which are not created automatically by 'django.contrib.auth.management.create_permissions'. See https://code.djangoproject.com/ticket/11154 Source: https://djangosnippets.org/snippets/2677/ Since we can't rely on 'get_for_model' we must fallback to 'get_by_natural_key'. However, this method doesn't automatically create missing 'ContentType' so we must ensure all the models' 'ContentType are created before running this method. We do so by un-registering the 'update_contenttypes' 'post_syncdb' signal and calling it in here just before doing everything. """ update_contenttypes(app, created_models, verbosity, **kwargs) app_models = models.get_models(app) # The permissions we're looking for as (content_type, (codename, name)) searched_perms = list() # The codenames and ctypes that should exist. ctypes = set() for model in app_models: opts = model._meta if opts.proxy: # Can't use 'get_for_model' here since it doesn't return # the correct 'ContentType' for proxy models. # See https://code.djangoproject.com/ticket/17648 app_label, model = opts.app_label, opts.object_name.lower() ctype = ContentType.objects.get_by_natural_key(app_label, model) ctypes.add(ctype) for perm in _get_all_permissions(opts, ctype): searched_perms.append((ctype, perm)) # Find all the Permissions that have a content_type for a model we're # looking for. We don't need to check for codenames since we already have # a list of the ones we're going to create. all_perms = set(Permission.objects.filter( content_type__in=ctypes, ).values_list( "content_type", "codename" )) objs = [ Permission(codename=codename, name=name, content_type=ctype) for ctype, (codename, name) in searched_perms if (ctype.pk, codename) not in all_perms ] Permission.objects.bulk_create(objs) if verbosity >= 2: for obj in objs: sys.stdout.write("Adding permission '%s'" % obj) models.signals.post_syncdb.connect(create_proxy_permissions) # See 'create_proxy_permissions' docstring to understand why we un-register # this signal handler. models.signals.post_syncdb.disconnect(update_contenttypes) 
+1
source

All Articles