【问题标题】:Migrating from auth.User to custom user model. Groups and permissions are always empty从 auth.User 迁移到自定义用户模型。组和权限始终为空
【发布时间】:2015-03-30 09:42:48
【问题描述】:

我正在将我的应用程序从 Django 1.4 迁移到 Django 1.7。我已经升级了所有第三方库和 Django 本身。运行 manage.py check 或使用 manage.py runserver' 时没有错误和警告。 现在我想转向自定义用户模型。我已经创建了模型,它是来自django.contrib.auth.models.User 的用户模型的直接副本,但有一个区别 - 我创建了自己的 PermissionMixin 基础,因为默认用户模型和我的自定义用户模型之间的反向关系发生冲突。

class PermissionsMixin(models.Model):
    is_superuser = models.BooleanField('superuser status', default=False)
    groups = models.ManyToManyField(
        Group, verbose_name='custom_groups', blank=True,
        related_name="custom_user_set", related_query_name="user")
    user_permissions = models.ManyToManyField(
        Permission, verbose_name='user permissions', blank=True,
        related_name="custom_user_set", related_query_name="user")

    class Meta:
        abstract = True

    def get_group_permissions(self, obj=None):
        permissions = set()
        for backend in auth.get_backends():
            if hasattr(backend, "get_group_permissions"):
                permissions.update(backend.get_group_permissions(self, obj))
        return permissions

    def get_all_permissions(self, obj=None):
        return _user_get_all_permissions(self, obj)

    def has_perm(self, perm, obj=None):

        # Active superusers have all permissions.
        if self.is_active and self.is_superuser:
            return True

        # Otherwise we need to check the backends.
        return _user_has_perm(self, perm, obj)

    def has_perms(self, perm_list, obj=None):
        for perm in perm_list:
            if not self.has_perm(perm, obj):
                return False
        return True

    def has_module_perms(self, app_label):
        # Active superusers have all permissions.
        if self.is_active and self.is_superuser:
            return True

        return _user_has_module_perms(self, app_label)


class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField('email address', max_length=254, unique=True)
    first_name = models.CharField('first name', max_length=30, blank=True)
    last_name = models.CharField('last name', max_length=30, blank=True)
    is_staff = models.BooleanField('staff status', default=False)
    is_active = models.BooleanField('active', default=True)
    date_joined = models.DateTimeField('date joined', default=timezone.now)

    USERNAME_FIELD = 'email'

在那之前一切都很好 - 迁移在数据库中创建了所需的表,我可以在管理员中修改自定义用户模型。 现在我想通过数据迁移将所有数据从auth.User 复制到我的users.CustomUser 模型中。下面的代码反映了我想做的事情:

from django.db import migrations, transaction


@transaction.atomic
def copy_old_users(apps, schema_editor):
    User = apps.get_model("auth", "User")
    CustomUser = apps.get_model("users", "CustomUser")

    fields = ['id', 'username', 'email', 'first_name', 'last_name',
              'is_staff', 'is_active', 'date_joined', 'is_superuser',
              'last_login']

    for user in User.objects.all():
        custom_user = CustomUser()
        for field in fields:
            setattr(custom_user, field, getattr(user, field))

        custom_user.save()

        custom_user.groups.add(*user.groups.all())
        custom_user.user_permissions.add(*user.user_permissions.all())

@transaction.atomic
def remove_new_users(apps, schema_editor):
    CustomUser = apps.get_model("users", "CustomUser")
    CustomUser.objects.all().delete()


class Migration(migrations.Migration):

    dependencies = [
        ('auth', '0003_auto_20150128_1715'),
        ('users', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(copy_old_users, remove_new_users),
    ]

我正在使用 MySQL。这里的问题是user.user_permissions.all()user.groups.all() 总是空的。我在 django shell 中尝试过同样的方法——空的。在管理员中 - groups 没有正确连接,user_permissions 是。我已签入数据库 - 这不应为空。进一步调查表明,以下代码检索了所需的对象:
User._meta.get_field('groups').rel.through.objects.filter(user_id=user.id)

user_permissions 也是如此。我可以遍历上述查询中的对象列表并访问Group 对象以在我的迁移中使用它。这一切都很好并且工作正常。

问题是:为什么标准方法不起作用?我是否以某种不好的方式访问对象?我是否错过了数据迁移中的某些内容?我应该导入(?!)一些特定的依赖项还是以某种特殊的方式检索 PermissionGroup 模型?

【问题讨论】:

  • 你能发布你的自定义用户模型吗?
  • @jbergantine 我已经用用户模型编辑了这个问题。
  • 我建议你把这个提交给 Django bug tracker。
  • 您是否需要介绍has_perm() and has_perms() methods?我已经完成了一个自定义用户模型,它定义了这些方法,并为每个方法实现了return True

标签: django django-migrations django-custom-user


【解决方案1】:

我没有足够的声誉来发表评论,但如果是一次性迁移,我建议您对 auth.groupauth.permission 模型进行 json 转储:

./manage.py dumpdata --indent=2 auth.group auth.permission > groups_and_perms.json

然后你可以再次加载它们:

./manage.py loaddata groups_and_perms.json

另外,组和权限将是ManyToMany 关系,不是吗?如果是这种情况,请尝试在您的 copy_old_users() 函数中使用 .save_m2m()

custom_user.save()

custom_user.groups.add(*user.groups.all())
custom_user.user_permissions.add(*user.user_permissions.all())

custom_user.save_m2m()

【讨论】:

  • 我不太确定你的建议是什么。我在我的问题中定义了“其他方式”解决方案,它比您的解决方案更容易实施并且确实有效。此外,如果您使用 .add,则无需致电 save_m2m - 它会为您节省费用。
猜你喜欢
  • 2013-01-31
  • 2017-08-05
  • 2016-07-31
  • 2013-07-23
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多