Search code examples
djangodjango-guardian

Django grant permissions on/ after saving object


I have a Django model which includes specific permissions. I want to be able to assign permissions to those users in the assigned_to field. I am using django-guardian to manage the permissions.

from django.db import models
from django.contrib.auth.models import User
from guardian.shortcuts import assign_perm


class Project(models.Model):
    ...
    assigned_to = models.ManyToManyField(
        User, default=None, blank=True, null=True
    )
    created_by = models.ForeignKey(
        User,
        related_name="%(app_label)s_%(class)s_related"
    )


    permissions = (
        ('view_project', 'View project'),
    )

I have tried to implement a custom save method. If I try and do it before the save:

    def save(self, *args, **kwargs):
        for user in self.assigned_to:
             assign_perm('view_project', user, self)
             super(Project, self).save(*args, **kwargs)

I get an error:

    ObjectNotPersisted: Object <project_name> needs to be persisted first

If I do it after the save (which I guess is wrong anyhow):

    def save(self, *args, **kwargs):
        super(Project, self).save(*args, **kwargs)
        for user in self.assigned_to:
             assign_perm('view_project', user, self)

I get an Type Error 'ManyRelatedManager' object is not iterable.

Should I be using a post-save signal for this? What is the best approach for what I assume is a common pattern?


Solution

  • The error is caused because the field itself is not iterable, you need to specify the queryset using filter or all:

    for user in self.assigned_to.all():
        assign_perm('view_project', user, self)
    

    However, as you commented, this needs to be done after the parent model instance is saved, so yes you can either create a post_save signal to accomplish this or save the M2M relations in your view after your call to save the parent instance.