2

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?

halfer
  • 19,824
  • 17
  • 99
  • 186
Darwin Tech
  • 18,449
  • 38
  • 112
  • 187

1 Answers1

2

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.

Fiver
  • 9,909
  • 9
  • 43
  • 63
  • Actually this doesn't work. The super method is called but `self.assigned_to.all()` is empty. It only works if I later explicitly add user: `assigned_to.add([users])`. isn't this because Django actually adds `ManyToMany` related fields after saving? – Darwin Tech May 21 '14 at 22:14
  • Yes, you are right. I was responding to your not iterable error and overlooked this. I'll update the answer. – Fiver May 21 '14 at 22:27