在 django 1.8 中将数据从原始用户模型迁移到自定义用户模型
Posted
技术标签:
【中文标题】在 django 1.8 中将数据从原始用户模型迁移到自定义用户模型【英文标题】:Migrate data from original User model to Custom User model in django 1.8 【发布时间】:2015-10-10 11:13:18 【问题描述】:我创建了一个自定义用户模型。 auth 数据库中已经有用户。因此,我使用数据迁移将数据迁移到我的自定义用户模型。
这就是我在自动迁移文件中进行数据迁移的方式(我从here找到的):
更新
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])
迁移后的问题,我无法创建新用户。我收到此错误:
重复键值违反唯一约束 "userauth_userauth_pkey" 详细信息:密钥 (id)=(3) 已存在。
似乎表格不同步。我该如何解决这个问题?
【问题讨论】:
能否展示模型自定义身份验证用户的代码? 【参考方案1】:在 Postgres 上,Django 处理为其数据库记录创建唯一主键的方式是使用 database sequence 从中获取新的主键。查看我自己的数据库,我发现如果我有一个名为 x 的表,那么 Django 将创建名为 x_id_seq
的序列。所以userauth_userauth
表的顺序是userauth_userauth_id_seq
。
现在,您使用原始 SQL 语句进行迁移的方式。这完全绕过了 Django 的 ORM,这意味着迁移不会触及新表的序列。执行此类原始迁移后,您应该将主键序列设置为不会与数据库中已有内容冲突的数字。借用this answer,那么你应该发出:
select setval('userauth_userauth_id_seq', max(id))
from userauth_userauth;
并对其他表执行相同类型的操作:如果它们的id
字段,则将它们自己的序列设置为最大值。 (如果您想知道,将使用的下一个值将通过nextval
获得,并且将比调用nextval
之前的序列值大一。)
在评论中,您想知道为什么创建新用户最终会奏效。可能发生的事情是您试图创建新用户,结果是这样的:
Django 从适当的序列中获得了一个新的主键。在这里,序列会增加。
Django 尝试保存新用户,但失败,因为它在上一步中得到的数字不是唯一的。
如果您这样做的次数足够多,那么每次尝试都会增加您的序列,因为无论事务如何,Postgres 都不会回滚序列。 documentation 说:
重要提示:因为序列是非事务性的,所以如果事务回滚,
setval
所做的更改不会撤消。
所以最终,序列会增加到超过表中已经存在的最大主键,并且从那时起它就可以工作了。
【讨论】:
是的,你就是男人!这解释了为什么它现在可以工作。我有几个测试时间来创建用户。你提到的序列也随之增加。好收获! @dev-jim 请注意,将答案标记为正确不与奖励它相同。既然答案似乎对你有所帮助,请考虑奖励给 Louis【参考方案2】:您使用的是什么数据库?听起来您的数据库有一个用于生成 3 之类的 id 的主键计数器。由于您使用主键创建了新行,因此您可能需要手动重置数据库计数器。关于 postgres 中的示例,请参阅How to reset postgres' primary key sequence when it falls out of sync?
【讨论】:
这是postrgres。但奇怪的是,当我今天尝试时,它有效!没有更多的错误..无法弄清楚为什么以上是关于在 django 1.8 中将数据从原始用户模型迁移到自定义用户模型的主要内容,如果未能解决你的问题,请参考以下文章
将旧 (Django 0.97) 模型数据导入/迁移到 Django 1.8 或更高版本
使用 --fake 后如何在 django 1.8 上重做迁移
Django 1.8 迁移:有啥方法可以从不再有模型的数据库表中获取数据?