Login

Create permissions for proxy models

Author:
charettes
Posted:
February 6, 2012
Language:
Python
Version:
1.3
Score:
0 (after 0 ratings)

Until [#11154] is fixed, django won't create permissions for proxy models for you as it does with other models, even the one you define using the permissions option on your models.

This snippet will make sure all permissions are create for proxy models. Just make sure this code gets loaded after the update_contenttypes handler is registered for the post_syncdb signal. Putting this code in one of your INSTALLED_APPS' afterdjango.contrib.contenttypes' should do it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import sys

from django.contrib.auth.management import _get_all_permissions
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.management import update_contenttypes
from django.contrib.contenttypes.models import ContentType
from django.db import models
        
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
        This method is inspired by `django.contrib.auth.managment.create_permissions`.
        
        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 model's `ContentType` are created before running this method.
        We do so by unregistering 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)
    # This will hold 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:
            # We 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):
                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 unregister
# this signal handler.
models.signals.post_syncdb.disconnect(update_contenttypes)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 4 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

dkdndes (on March 1, 2012):

Hi,

I get in create_proxy_permissions Permission.objects.bulk_create(objs) AttributeError: 'PermissionManager' object has no attribute 'bulk_create'

Any idea?

Regards,

Peter

#

vbretsch (on March 2, 2012):

Hi Charettes,

i get the same error message 'dkdndes' described, when running a sync db command on a totally clean database.

Django code version is: (1, 3, 0, 'final', 0).

Am i doing something wrong?

Best regards, Volker

#

Nagyman (on March 5, 2012):

Unfortunately, bulk_create is new in the development version (1.4)

#

fspegni (on September 21, 2013):

Hi,

thanks for the useful snippet. I had to make 2 small modifications:

line 38:
    for perm in _get_all_permissions(opts, ctype):

line 30:
    app_models = django.db.models.get_models(app)

(in order to make the modified line 23 to work, I had to import django). Actually I don't know why your line 23 didn't work for me, but it raised me an exception like:

AttributeError: 'module' object has no attribute 'get_models'

to verify, in a django shell i run:

$ from django.db import models
$ models.get_models("foo")

and it executed it. nevertheless, the problem at line 38 seems a real bug (in django 1.5.1)

thanks again

#

Please login first before commenting.