在现有的 django-cms 项目中使用 django-custom-user
Using django-custom-user in existing django-cms project
我有一个现有的 django-cms 版本。 3.1.3 项目,我想用 django-custom-user 中找到的模型替换默认的 django 用户模型(将电子邮件作为我的用户的用户名)。我已将 custom_user
应用程序添加到我的 INSTALLED_APPS
并设置 AUTH_USER_MODEL = 'custom_user.EmailUser'
。最后我应用了迁移。
我的自定义模型似乎一切正常,但是 django-cms 模型引用了 auth_user
table (GlobalPagePermission
, PagePermission,
PageUser
和 UserSettings
) 未更新为具有对新自定义用户 table.
的外键引用
django-cms documentation 表示通常建议在项目开始时添加自定义用户模型,但我现在处于项目中间,非常希望避免删除我的 cms 模型(带数据)使其工作。
如果我在一个项目的开始阶段,并且在迁移 django-cms 模型之前添加了自定义用户模型,那么 django-cms 模型是否真的会引用自定义用户模型 table而不是默认的?
我有什么方法可以为 django-cms 模型进行迁移,以便他们使用新的自定义用户模型而不是默认模型?
更新
我正在努力实现 yakky 的建议:
from __future__ import unicode_literals
from django.conf import settings
from django.db import models, migrations
import django.db.models.deletion
from django.utils.translation import ugettext_lazy as _
def up(apps, schema_editor):
PageUser = apps.get_model("cms", "PageUser")
db_alias = schema_editor.connection.alias
for pu in PageUser.objects.all():
pu['emailuser_ptr_id'] = pu['user_ptr_id']
pu.save()
def down(apps, schema_editor):
PageUser = apps.get_model("cms", "PageUser")
db_alias = schema_editor.connection.alias
for pu in PageUser.objects.all():
pu['user_ptr_id'] = pu['emailuser_ptr_id']
pu.save()
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
(‘myapp’, ‘previous-migration’),
]
operations = [
migrations.RenameField(
model_name='PageUser',
old_name='user_ptr_id',
new_name='user_ptr_id_old',
),
migrations.AddField(
model_name='PageUser',
name='emailuser_ptr_id',
field=models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, verbose_name=_('user'), blank=True),
preserve_default=True,
),
migrations.RunPython(up, down),
migrations.RemoveField(
model_name='PageUser',
name='user_ptr_id_old',
),
]
失败,KeyError: ('myapp', u'pageuser')
表明它在我的自定义应用程序中而不是在 cms 应用程序中查找 PageUser
模型。如何将这些迁移应用到 cms 模型?
据说在项目生命周期的中间替换 Django 用户模型是不可取的(参见 https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model),因为 Django 不提供任何方法来在创建关系后修改关系,以替换自定义用户模型,您可以编写一个自定义迁移,更改 Django CMS 模型中的外键以指向并为新用户模型创建一个新的外键。
类似于:
...
migrations.RenameField(
model_name='globalpagepermission',
old_name='user',
new_name='user_old',
),
migrations.AddField(
model_name='globalpagepermission',
name='user',
field=models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, verbose_name=_('user'), blank=True),
preserve_default=True,
),
migrations.RunPython(copy_data),
migrations.RemoveField(
model_name='globalpagepermission',
name='user_old',
),
...
对任何相关模型/字段重复。
copy_data
方法会将外键的值从 user_old
复制到 user
代码完全未经测试,但总体思路应该可行。
或者,您可以编写 RunSQL 迁移以获得相同的结果。
要使新模型起作用,还必须存在具有相同主键的用户。
多亏了https://code.djangoproject.com/ticket/25313,我才得以成功。这就是我所做的:
备份了我的数据库!
创建了一个新应用 email_username 来保存我的用户模型(按照 link 中的建议命名为 User)。一个新的应用程序是必要的,因为我的主应用程序 (myapp) 依赖于 django-cms,如果我将我的新用户模型放在 myapp 中,django-cms 将依赖于我的应用程序——这将创建一个循环引用.
class User(AbstractEmailUser):
# Needed to add username, first_name and last_name here, because cms.PageUser model depends on these fields
username = models.CharField(max_length=100, verbose_name=_('username'))
first_name = models.CharField(max_length=100, verbose_name=_('first_name'))
last_name = models.CharField(max_length=100, verbose_name=_('last_name'))
class Meta:
db_table = 'auth_user' # the model will use the existing auth_user table (at first)
在settings.py
中设置AUTH_USER_MODEL = ‘email_username.User’
- 删除了 myapp 的所有迁移并截断了
django_migrations
table
- 运行
manage.py makemigrations
得到了
Cannot resolve bases for [] This can
happen if you are inheriting models from an app with migrations (e.g.
contrib.auth) in an app with no migrations; see
https://docs.djangoproject.com/en/1.8/topics/migrations/#dependencies
for more
...所以我再次从 settings.py
、运行 makemigrations
中删除了 cms
应用程序,现在成功了,然后是 re-added 和 运行 makemigrations
再一次。
- 运行
manage.py migrate --fake
,却得到了
Cannot resolve bases for [ModelState: 'djangocms_file.File', ModelState: 'djangocms_video.Video', ModelState: 'djangocms_link.Link', ModelState: 'djangocms_googlemap.GoogleMap', ModelState: 'djangocms_picture.Picture', ModelState: 'djangocms_teaser.Teaser']
...所以我也从 settings.py
、运行 migrate --fake
、re-added 应用程序和 migrate --fake
中删除了这些应用程序。
- 从新用户模型中删除了
db_table
设置,运行 makemigrations
后跟 migrate
(没有假!)
现在一切似乎都井井有条。以前引用标准 auth_user table 的所有外键现在都引用我的新用户模型的 table。由于 db_table 技巧,现有用户甚至被 t运行 转移。
我有一个现有的 django-cms 版本。 3.1.3 项目,我想用 django-custom-user 中找到的模型替换默认的 django 用户模型(将电子邮件作为我的用户的用户名)。我已将 custom_user
应用程序添加到我的 INSTALLED_APPS
并设置 AUTH_USER_MODEL = 'custom_user.EmailUser'
。最后我应用了迁移。
我的自定义模型似乎一切正常,但是 django-cms 模型引用了 auth_user
table (GlobalPagePermission
, PagePermission,
PageUser
和 UserSettings
) 未更新为具有对新自定义用户 table.
django-cms documentation 表示通常建议在项目开始时添加自定义用户模型,但我现在处于项目中间,非常希望避免删除我的 cms 模型(带数据)使其工作。
如果我在一个项目的开始阶段,并且在迁移 django-cms 模型之前添加了自定义用户模型,那么 django-cms 模型是否真的会引用自定义用户模型 table而不是默认的?
我有什么方法可以为 django-cms 模型进行迁移,以便他们使用新的自定义用户模型而不是默认模型?
更新
我正在努力实现 yakky 的建议:
from __future__ import unicode_literals
from django.conf import settings
from django.db import models, migrations
import django.db.models.deletion
from django.utils.translation import ugettext_lazy as _
def up(apps, schema_editor):
PageUser = apps.get_model("cms", "PageUser")
db_alias = schema_editor.connection.alias
for pu in PageUser.objects.all():
pu['emailuser_ptr_id'] = pu['user_ptr_id']
pu.save()
def down(apps, schema_editor):
PageUser = apps.get_model("cms", "PageUser")
db_alias = schema_editor.connection.alias
for pu in PageUser.objects.all():
pu['user_ptr_id'] = pu['emailuser_ptr_id']
pu.save()
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
(‘myapp’, ‘previous-migration’),
]
operations = [
migrations.RenameField(
model_name='PageUser',
old_name='user_ptr_id',
new_name='user_ptr_id_old',
),
migrations.AddField(
model_name='PageUser',
name='emailuser_ptr_id',
field=models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, verbose_name=_('user'), blank=True),
preserve_default=True,
),
migrations.RunPython(up, down),
migrations.RemoveField(
model_name='PageUser',
name='user_ptr_id_old',
),
]
失败,KeyError: ('myapp', u'pageuser')
表明它在我的自定义应用程序中而不是在 cms 应用程序中查找 PageUser
模型。如何将这些迁移应用到 cms 模型?
据说在项目生命周期的中间替换 Django 用户模型是不可取的(参见 https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model),因为 Django 不提供任何方法来在创建关系后修改关系,以替换自定义用户模型,您可以编写一个自定义迁移,更改 Django CMS 模型中的外键以指向并为新用户模型创建一个新的外键。
类似于:
...
migrations.RenameField(
model_name='globalpagepermission',
old_name='user',
new_name='user_old',
),
migrations.AddField(
model_name='globalpagepermission',
name='user',
field=models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, verbose_name=_('user'), blank=True),
preserve_default=True,
),
migrations.RunPython(copy_data),
migrations.RemoveField(
model_name='globalpagepermission',
name='user_old',
),
...
对任何相关模型/字段重复。
copy_data
方法会将外键的值从 user_old
复制到 user
代码完全未经测试,但总体思路应该可行。
或者,您可以编写 RunSQL 迁移以获得相同的结果。
要使新模型起作用,还必须存在具有相同主键的用户。
多亏了https://code.djangoproject.com/ticket/25313,我才得以成功。这就是我所做的:
备份了我的数据库!
创建了一个新应用 email_username 来保存我的用户模型(按照 link 中的建议命名为 User)。一个新的应用程序是必要的,因为我的主应用程序 (myapp) 依赖于 django-cms,如果我将我的新用户模型放在 myapp 中,django-cms 将依赖于我的应用程序——这将创建一个循环引用.
class User(AbstractEmailUser): # Needed to add username, first_name and last_name here, because cms.PageUser model depends on these fields username = models.CharField(max_length=100, verbose_name=_('username')) first_name = models.CharField(max_length=100, verbose_name=_('first_name')) last_name = models.CharField(max_length=100, verbose_name=_('last_name')) class Meta: db_table = 'auth_user' # the model will use the existing auth_user table (at first)
在
settings.py
中设置- 删除了 myapp 的所有迁移并截断了
django_migrations
table - 运行
manage.py makemigrations
得到了
AUTH_USER_MODEL = ‘email_username.User’
Cannot resolve bases for [] This can happen if you are inheriting models from an app with migrations (e.g. contrib.auth) in an app with no migrations; see https://docs.djangoproject.com/en/1.8/topics/migrations/#dependencies for more
...所以我再次从 settings.py
、运行 makemigrations
中删除了 cms
应用程序,现在成功了,然后是 re-added 和 运行 makemigrations
再一次。
- 运行
manage.py migrate --fake
,却得到了
Cannot resolve bases for [ModelState: 'djangocms_file.File', ModelState: 'djangocms_video.Video', ModelState: 'djangocms_link.Link', ModelState: 'djangocms_googlemap.GoogleMap', ModelState: 'djangocms_picture.Picture', ModelState: 'djangocms_teaser.Teaser']
...所以我也从 settings.py
、运行 migrate --fake
、re-added 应用程序和 migrate --fake
中删除了这些应用程序。
- 从新用户模型中删除了
db_table
设置,运行makemigrations
后跟migrate
(没有假!)
现在一切似乎都井井有条。以前引用标准 auth_user table 的所有外键现在都引用我的新用户模型的 table。由于 db_table 技巧,现有用户甚至被 t运行 转移。