1

I am trying to migrate my models to use Guardian permissions. At this point I have:

class Data(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    class Meta:
        permissions = (
            ('view', 'View'),
            ('edit', 'Edit'),
            ('owner', 'Owner'),
        )

I created one migration that added the new permissions, and in a custom migration I am trying to assign the permissions like this:

def assignDataPermissions(apps, schema_editor):
    Data = apps.get_model('api', 'Data')
    for data in Data.objects.all():
        assign_perm('api.owner', data.user, data)


class Migration(migrations.Migration):
    dependencies = [
        ('api', '0169_auto_20180304_1619'),
    ]

    operations = [
        migrations.RunPython(assignDataPermissions)
    ]

This fails with guardian.exceptions.NotUserNorGroup: User/AnonymousUser or Group instance is required (got EmailUser object).

Is there a better/proper way of migrating to Guardian? If not, how do I make it see my custom User class?

David R.
  • 855
  • 8
  • 17

2 Answers2

2

I ended up using higher level workaround. Inside the migration, data.user is actually an object of __fake.EmailUser, while get_user_model() returns custom_user.models.EmailUser. As a result Guardian fails the check isinstance(identity, get_user_model()).

My workaround(hack?) is to explicitly get the EmailUser object from the database corresponding to data.user. Like so:

def assignDataPermissions(apps, schema_editor):
    Data = apps.get_model('api', 'Data')
    User = get_user_model()
    for data in Data.objects.all():
        user = User.objects.get(id=data.user_id)
        assign_perm('api.owner', user, data)
David R.
  • 855
  • 8
  • 17
1

In general, loading external libraries in migrations is prone to errors.

Try something low-level like that:

def assignDataPermissions(apps, schema_editor):
    Data = apps.get_model('api', 'Data')
    Permission = apps.get_model('auth', 'Permission')
    owner_api = Permission.objects.get(content_type__applabel='api', codename='owner')
    UserObjectPermission = apps.get_model('guardian', 'UserObjectPermission')
    for data in Data.objects.all():
        UserObjectPermission.objects.create(permission=owner_api, user=data.user, content_object=data)
Adam Dobrawy
  • 1,145
  • 13
  • 14
  • Thanks! I managed to coerce `assign_perm` by explicitly fetching the user object matching `data.user` from the database. See my answer. – David R. Mar 05 '18 at 15:25