62👍
Django’s Permission
model requires a ContentType
instance.
I think one way around it is creating a dummy ContentType
that isn’t related to any model (the app_label
and model
fields can be set to any string value).
If you want it all clean and nice, you can create a Permission
proxy model that handles all the ugly details of the dummy ContentType
and creates “modelless” permission instances. You can also add a custom manager that filters out all Permission
instances related to real models.
230👍
For those of you, who are still searching:
You can create an auxiliary model with no database table. That model can bring to your project any permission you need. There is no need to deal with ContentType or create Permission objects explicitly.
from django.db import models
class RightsSupport(models.Model):
class Meta:
managed = False # No database table creation or deletion \
# operations will be performed for this model.
default_permissions = () # disable "add", "change", "delete"
# and "view" default permissions
permissions = (
('customer_rights', 'Global customer rights'),
('vendor_rights', 'Global vendor rights'),
('any_rights', 'Global any rights'),
)
Right after manage.py makemigrations
and manage.py migrate
you can use these permissions like any other.
# Decorator
@permission_required('app.customer_rights')
def my_search_view(request):
…
# Inside a view
def my_search_view(request):
request.user.has_perm('app.customer_rights')
# In a template
# The currently logged-in user’s permissions are stored in the template variable {{ perms }}
{% if perms.app.customer_rights %}
<p>You can do any customer stuff</p>
{% endif %}
- [Django]-Altering one query parameter in a url (Django)
- [Django]-How can i test for an empty queryset in Django?
- [Django]-Django "xxxxxx Object" display customization in admin action sidebar
56👍
Following Gonzalo’s advice, I used a proxy model and a custom manager to handle my "modelless" permissions with a dummy content type.
from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
class GlobalPermissionManager(models.Manager):
def get_queryset(self):
return super(GlobalPermissionManager, self).\
get_query_set().filter(content_type__name='global_permission')
class GlobalPermission(Permission):
"""A global permission, not attached to a model"""
objects = GlobalPermissionManager()
class Meta:
proxy = True
def save(self, *args, **kwargs):
ct, created = ContentType.objects.get_or_create(
name="global_permission", app_label=self._meta.app_label
)
self.content_type = ct
super(GlobalPermission, self).save(*args, **kwargs)
- [Django]-How to test "render to template" functions in django? (TDD)
- [Django]-Saving ModelForm error(User_Message could not be created because the data didn't validate)
- [Django]-How to pass django rest framework response to html?
11👍
Fix for Chewie’s answer in Django 1.8, which as been requested in a few comments.
It says in the release notes:
The name field of django.contrib.contenttypes.models.ContentType has been
removed by a migration and replaced by a property. That means it’s not
possible to query or filter a ContentType by this field any longer.
So it’s the ‘name’ in reference in ContentType that the uses not in GlobalPermissions.
When I fix it I get the following:
from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
class GlobalPermissionManager(models.Manager):
def get_queryset(self):
return super(GlobalPermissionManager, self).\
get_queryset().filter(content_type__model='global_permission')
class GlobalPermission(Permission):
"""A global permission, not attached to a model"""
objects = GlobalPermissionManager()
class Meta:
proxy = True
verbose_name = "global_permission"
def save(self, *args, **kwargs):
ct, created = ContentType.objects.get_or_create(
model=self._meta.verbose_name, app_label=self._meta.app_label,
)
self.content_type = ct
super(GlobalPermission, self).save(*args)
The GlobalPermissionManager class is unchanged but included for completeness.
If using Django admin to create/edit these permissions, think of removing the content_type field to avoid confusion:
class GlobalPermissionAdmin(admin.ModelAdmin):
list_display = ("name", "codename")
exclude = ("content_type",)
admin.site.register(GlobalPermission, GlobalPermissionAdmin)
- [Django]-Django: Using F arguments in datetime.timedelta inside a query
- [Django]-How to repeat a "block" in a django template
- [Django]-Django: Fat models and skinny controllers?
5👍
This is alternative solution. First ask yourself: Why not create a Dummy-Model which really exists in DB but never ever gets used, except for holding permissions? That’s not nice, but I think it is valid and straight forward solution.
from django.db import models
class Permissions(models.Model):
can_search_blue_flower = 'my_app.can_search_blue_flower'
class Meta:
permissions = [
('can_search_blue_flower', 'Allowed to search for the blue flower'),
]
Above solution has the benefit, that you can use the variable Permissions.can_search_blue_flower
in your source code instead of using the literal string “my_app.can_search_blue_flower”. This means less typos and more autocomplete in IDE.
- [Django]-Django.contrib.gis.db.backends.postgis vs django.db.backends.postgresql_psycopg2
- [Django]-When to use Serializer's create() and ModelViewset's perform_create()
- [Django]-Check if celery beat is up and running
2👍
You can use the proxy model
for this with a dummy content type.
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
class CustomPermission(Permission):
class Meta:
proxy = True
def save(self, *args, **kwargs):
ct, created = ContentType.objects.get_or_create(
model=self._meta.verbose_name, app_label=self._meta.app_label,
)
self.content_type = ct
super(CustomPermission, self).save(*args)
Now you can create the permission with just name
and codename
of the permission from the CustomPermission
model.
CustomPermission.objects.create(name='Can do something', codename='can_do_something')
And you can query and display only the custom permissions in your templates like this.
CustomPermission.objects.filter(content_type__model='custom permission')
- [Django]-Django-debug-toolbar not showing up
- [Django]-POST jQuery array to Django
- [Django]-Can a dictionary be passed to django models on create?
2👍
For my part, for any larger project, I find it useful to have a generic app that isn’t really part of my project’s data model per se – I typically call it "projectlibs". It’s a simple django app where I put things like fixtures for imports, templatetags that can be reused for multiple apps, etc. Some of it is template stuff I find myself re-using often, so the added benefit of having that type of stuff in an app is that it’s reusable for other projects.
So inside that projectlibs/models.py
, you could:
You could create that "meta app", in essence, and assign the content_type
to some dummy class:
class UserRightsSupport(models.Model):
class Meta:
default_permissions = () # disable defaults add, delete, view, change perms
permissions = (
("perm_name", "Verbose description"),
)
- [Django]-How to change site title, site header and index title in Django Admin?
- [Django]-Uninstall Django completely
- [Django]-How to check whether the user is anonymous or not in Django?
0👍
All answers are bad for me except this:
content_type = ContentType.objects.get_for_model(Permission)
Permission.objects.create(
content_type=content_type,
name='...', codename='...',
)
which handles model-less permissions
without adding new models, but by adding new values.
- [Django]-Foreign key from one app into another in Django
- [Django]-What's the difference between `from django.conf import settings` and `import settings` in a Django project
- [Django]-Django-Bower + Foundation 5 + SASS, How to configure?
0👍
I think that User
model substitution do the trick (see Django documentation: https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#substituting-a-custom-user-model)
Next on that model we can add Meta
class with permissions and at the end we need to add our User
model in settings.py
.
Here is my example of user.py
file:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
class Meta:
default_permissions = [] # disable "add", "change", "delete"
# and "view" default permissions
permissions = [
('customer_rights', 'Global customer rights'),
('vendor_rights', 'Global vendor rights'),
('any_rights', 'Global any rights'),
]
and in settings.py
:
AUTH_USER_MODEL = 'myapp.User'
- [Django]-Create empty queryset by default in django form fields
- [Django]-Django Rest Framework — no module named rest_framework
- [Django]-Data Mining in a Django/Postgres application