【问题标题】:Using django-custom-user in existing django-cms project在现有的 django-cms 项目中使用 django-custom-user
【发布时间】:2016-01-17 21:55:03
【问题描述】:

我有一个现有的 django-cms 版本。 3.1.3 项目,我想用django-custom-user 中的模型替换默认的 django User 模型(将电子邮件作为我的用户的用户名)。我已将custom_user 应用程序添加到我的INSTALLED_APPS 并设置AUTH_USER_MODEL = 'custom_user.EmailUser'。最后我应用了迁移。

在我的自定义模型中似乎一切正常,但是引用 auth_user 表(GlobalPagePermissionPagePermission,PageUserUserSettings)的 django-cms 模型没有更新为对新自定义用户表的外键引用。

django-cms documentation 表示通常建议在项目开始时添加自定义用户模型,但我现在处于项目中间,非常希望避免删除我的 cms 模型(与数据)使其工作。

如果我在一个项目的开始阶段,并且在迁移 django-cms 模型之前添加了自定义用户模型,那么 django-cms 模型实际上会获得对自定义用户模型表的引用而不是默认的吗?

我有什么方法可以迁移 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 django-cms django-custom-user


【解决方案1】:

据说在项目生命周期的中间替换 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 迁移来获得相同的结果。

还必须存在具有相同主键的用户,新模型才能正常工作。

【讨论】:

  • 准备了自定义迁移,但是如何在 django-cms 等外部应用程序中迁移模型?
  • 迁移可以访问任何模型,并且不限于当前应用程序中的模型
【解决方案2】:

感谢https://code.djangoproject.com/ticket/25313 我设法让它工作。这就是我所做的:

  1. 备份了我的数据库!

  2. 创建了一个新的应用 email_username 来保存我的用户模型(链接中推荐的名为 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)
    
  3. settings.py中设置AUTH_USER_MODEL = ‘email_username.User’

  4. 删除了 myapp 的所有迁移并截断了 django_migrations
  5. manage.py makemigrations得到了

无法解析 [] 的基数 这可以 如果您从具有迁移的应用程序继承模型(例如 contrib.auth) 在没有迁移的应用程序中;看 https://docs.djangoproject.com/en/1.8/topics/migrations/#dependencies 了解更多

...所以我从settings.py 中删除了cms 应用程序,再次运行makemigrations,现在成功了,然后重新添加并再次运行makemigrations

  1. 跑了manage.py migrate --fake,但是得到了

无法解析 [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,重新添加了这些应用程序并再次migrate --fake

  1. 从新的用户模型中删除了db_table 设置,运行makemigrations,然后运行migrate(没有假!)

现在一切似乎都井井有条。之前引用标准 auth_user 表的所有外键现在都引用了我的新用户模型的表。由于 db_table 技巧,现有用户甚至被转移。

【讨论】:

    最近更新 更多