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' after
django.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
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 8 months ago
Comments
Hi,
I get in create_proxy_permissions Permission.objects.bulk_create(objs) AttributeError: 'PermissionManager' object has no attribute 'bulk_create'
Any idea?
Regards,
Peter
#
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
#
Unfortunately, bulk_create is new in the development version (1.4)
#
Hi,
thanks for the useful snippet. I had to make 2 small modifications:
(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:
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.