I'm migrating my app from Django 1.4 to Django 1.7. I have already upgraded all third party libraries and Django itself. No errors and warnings on running manage.py check
or when using manage.py runserver
'.
Now I want to move to a custom user model. I have created the model and it's a direct copy of the User model from django.contrib.auth.models.User
with one difference - I have created my own PermissionMixin base because with the default one the reverse relationships were clashing between the default User model and my custom User model.
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'
Until that point everything is fine - the migration creates the required tables in the database and I can modify the Custom user model in admin.
Now I want to copy all the data from auth.User
to my users.CustomUser
model with a datamigration. The below code reflects what I would like to do:
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),
]
I am using MySQL. The problem here is user.user_permissions.all()
and user.groups.all()
are always empty. I have tried the same in the django shell - empty. In admin - the groups
aren't properly attached and the user_permissions
are. I have checked in the database - this should not be empty. Further investigation showed that the following code retrieves the required objects:
User._meta.get_field('groups').rel.through.objects.filter(user_id=user.id)
and it's the same with user_permissions
. I can iterate through the objects list from the above query and access the Group
object to use it in my migration. This is all well and working.
Questions are: why doesn't the standard way work? Am I accessing the objects in some bad way? Have I missed something in data migration? Should I import(?!) some specific dependency or retrieve the Permission
and Group
models in some special way?