在django 1.8中将数据从原始用户模型迁移到自定义用户模型 [英] Migrate data from original User model to Custom User model in django 1.8

查看:135
本文介绍了在django 1.8中将数据从原始用户模型迁移到自定义用户模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个自定义用户模型。 auth数据库中已经有用户。因此,我使用数据迁移将数据迁移到我的自定义用户模型。



这就是我在自动迁移文件中进行数据迁移的方式(我从此处):



已更新

 从__future__导入unicode_literals 

从django.db导入模型,迁移


类Migration(migrations.Migration):

依赖关系= [
('userauth','0002_auto_20150721_0605'),
]

操作= [
迁移。RunSQL('INSERT INTO userauth_userauth SELECT * FROM auth_user'),
迁移。RunSQL('INSERT INTO userauth_userauth_groups SELECT * FROM auth_user_groups'),
migrations.RunSQL ('INSERT INTO userauth_userauth_user_permissions SELECT * FROM auth_user_user_permissions'),
]

models.py

 类UserMana ger(BaseUserManager):
def _create_user(自身,用户名,电子邮件,密码,is_staff,is_superuser,** extra_fields):
now = timezone.now()
如果不是用户名:
提高ValueError(_('必须设置给定的用户名'))
电子邮件= self.normalize_email(电子邮件)
用户= self.model(用户名=用户名,电子邮件=电子邮件,
is_staff = is_staff,is_active = False,
is_superuser = is_superuser,last_login = now,
date_joined = now,** extra_fields)
user.set_password(password)
user.save (using = self._db)
if is_staff:
group = Group.objects.get(name ='normal')
user.groups.add(group)
返回用户

def create_user(自己,用户名,电子邮件=无,密码=无,** extra_fields):
返回self._create_user(用户名,电子邮件,密码,False,False,
** extra_fields)

def create_superuser(自己,用户名,电子邮件,密码,** extra_fields):
user = self._create_user(用户名,电子邮件,密码,True,True,
** extra_fields)
user.is_active =真实
user.save(using = self._db)
返回用户


类UserAuth(AbstractBaseUser,PermissionsMixin):
#原始字段
用户名= models.CharField(_('用户名'),max_length = 30,唯一= True,
help_text = _('必填。少于30个字符。字母,数字和@ /。/ + /-/ _字符'),
验证者= [
验证者.RegexValidator(re.compile('^ [\w。@ +-] + $' ),_('输入有效的用户名。'),_('无效'))
])
first_name = models.CharField(_('first''),max_length = 30,blank = True,null = True)
last_name = models.CharField(_('lastname'),max_length = 30,blank = True,null = True)
email = models.EmailField(_('email address'),max_length = 255,unique = True)
is_staff = models.BooleanField(_('staff status'),default = False,
help_text = _('指定用户是否可以登录此管理站点。'))
is_active = models.BooleanField(_('active'),默认= False,
help_text = _('指定是否应将此用户视为活动用户。请取消选择此用户'))
date_joined =模型.DateTimeField(_('加入日期'),默认为timezone.now)
#附加字段
full_name =模型s.CharField(_('Full Name'),max_length = 600,blank = True,null = True)
profileImage = models.ImageField(upload_to = upload,blank = True,null = True,
help_text = _(请上传图片))
BioUser = models.TextField(blank = True,null = True)
Social_link = models.URLField(blank = True,null = True)

对象= UserManager()
USERNAME_FIELD ='用户名'
REQUIRED_FIELDS = []

class Meta:
verbose_name = _(' user')
verbose_name_plural = _('users')

def get_full_name(self):
返回self.full_name

def get_short_name(self) :
return self.first_name

def email_user(self,subject,message,from_email = None):
send_mail(主题,消息,from_email,[self.email])

迁移后的问题是,我无法创建新用户。我收到此错误:


重复的键值违反了唯一约束
userauth_userauth_pkey详情:键(id)=(3)


表似乎不同步。如何解决此问题?

解决方案

在Postgres上,Django处理数据库记录的唯一主键的方式是使用数据库序列,它从中获取新的主键。在我自己的数据库中,我发现如果我有一个名为 x 的表,那么Django将以 x _id_seq 。因此, userauth_userauth 表的顺序为 userauth_userauth_id_seq



<现在,您进行迁移的方式就是使用原始SQL语句。这完全绕过了Django的ORM,这意味着迁移不会影响新表的顺序。执行这种原始迁移后,您应该做的是将主键序列设置为不会与数据库中已有内容冲突的数字。从此答案中借用,然后应发出:

 从userauth_userauth中选择setval('userauth_userauth_id_seq',max(id))
;

并对其他表执行相同类型的操作:如果他们的 id 字段。 (如果您想知道,将通过 nextval ,并且比调用 nextval 之前的序列值大一。)



在一条评论中,您想知道为什么最终创建新用户有效。可能发生的事情是您正在尝试创建新用户,结果如下:


  1. Django从中获得了新的主键适当的顺序。


  2. Django尝试保存新用户,但失败,因为上一步获得的数字不是唯一的。

  3. >

如果您进行了多次,则每次尝试都会增加序列,因为与交易无关 ,Postgres不会回滚序列。 文档说:


重要提示:由于序列是非事务性的,因此 setval 所做的更改不会被撤消如果事务回滚了。


因此,最终,序列从表中已经存在的最大主键开始增加,从那以后开始可以。


I am created a custom user model. There were already have users in the auth database. So, I using the data migration to migrate the data to my custom user model.

This is how I did the data migration in the auto migration file (which I found from here):

UPDATED

from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
        ('userauth', '0002_auto_20150721_0605'),
    ]

    operations = [
        migrations.RunSQL('INSERT INTO userauth_userauth SELECT * FROM auth_user'),
        migrations.RunSQL('INSERT INTO userauth_userauth_groups SELECT * FROM auth_user_groups'),
        migrations.RunSQL('INSERT INTO userauth_userauth_user_permissions SELECT * FROM auth_user_user_permissions'),
    ]

models.py

class UserManager(BaseUserManager):
        def _create_user(self, username, email, password, is_staff, is_superuser, **extra_fields):
            now = timezone.now()
            if not username:
              raise ValueError(_('The given username must be set'))
            email = self.normalize_email(email)
            user = self.model(username=username, email=email,
                     is_staff=is_staff, is_active=False,
                     is_superuser=is_superuser, last_login=now,
                     date_joined=now, **extra_fields)
            user.set_password(password)
            user.save(using=self._db)
            if not is_staff:
                group = Group.objects.get(name='normal')
                user.groups.add(group)
            return user

        def create_user(self, username, email=None, password=None, **extra_fields):
            return self._create_user(username, email, password, False, False,
                     **extra_fields)

        def create_superuser(self, username, email, password, **extra_fields):
            user=self._create_user(username, email, password, True, True,
                         **extra_fields)
            user.is_active=True
            user.save(using=self._db)
            return user


    class UserAuth(AbstractBaseUser, PermissionsMixin):
        #original fields
        username = models.CharField(_('username'), max_length=30, unique=True,
        help_text=_('Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters'),
        validators=[
          validators.RegexValidator(re.compile('^[\w.@+-]+$'), _('Enter a valid username.'), _('invalid'))
        ])
        first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True)
        last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True)
        email = models.EmailField(_('email address'), max_length=255, unique=True)
        is_staff = models.BooleanField(_('staff status'), default=False,
        help_text=_('Designates whether the user can log into this admin site.'))
        is_active = models.BooleanField(_('active'), default=False,
        help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'))
        date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
      #additional fields
        full_name =  models.CharField(_('Full Name'), max_length=600, blank=True, null=True)
        profileImage = models.ImageField(upload_to="upload",blank=True,null=True,
        help_text = _("Please upload your picture"))
        BioUser =  models.TextField(blank=True,null=True)
        Social_link = models.URLField(blank=True,null=True)

        objects = UserManager()
        USERNAME_FIELD = 'username'
        REQUIRED_FIELDS = []

        class Meta:
            verbose_name = _('user')
            verbose_name_plural = _('users')

        def get_full_name(self):
            return self.full_name

        def get_short_name(self):
            return self.first_name

        def email_user(self, subject, message, from_email=None):
            send_mail(subject, message, from_email, [self.email])

The problem after the migration, I can't create new user. I get this error:

duplicate key value violates unique constraint "userauth_userauth_pkey" DETAIL: Key (id)=(3) already exists.

Seem the table is out of sync. How do I fix this?

解决方案

On Postgres, the way Django handles creating unique primary keys for its database records is by using a database sequence from which it gets new primary keys. Looking in my own database, I see that if I have a table named x, then Django creates the sequence under the name x_id_seq. So the sequence for your userauth_userauth table would be userauth_userauth_id_seq.

Now, the way you did your migration you went with raw SQL statements. This completely bypasses Django's ORM, which means that the sequences for the new tables were not touched by the migration. What you should do after performing such a raw migration is to set the primary key sequence to a number that won't clash with what is already in the database. Borrowing from this answer, then you should issue:

select setval('userauth_userauth_id_seq', max(id)) 
       from userauth_userauth;

And perform the same kind of operation for the other tables: set their own sequences to the max value if their id field. (If you wonder, the next value that will used will be obtained through nextval and will be equal to one more than the value of the sequence before nextval is called.)

In a comment you wondered why creating new users eventually worked. Probably what happened is that you were trying to create new users and it went like this:

  1. Django got a new primary key from the appropriate sequence. Here the sequence gets incremented.

  2. Django tried to save the new user, which failed because the number it got in the previous step was not unique.

If you do this enough times, your sequence will get incremented for each try because irrespective of transactions, Postgres does not rollback sequences. The documentation says:

Important: Because sequences are non-transactional, changes made by setval are not undone if the transaction rolls back.

So eventually, the sequence increases past the maximum primary key already in the table, and from that point onwards it works.

这篇关于在django 1.8中将数据从原始用户模型迁移到自定义用户模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆