Python Django 1.7数据迁移和用户组

Python Django 1.7数据迁移和用户组,python,django,migration,Python,Django,Migration,我正在尝试使用django 1.7本机迁移系统实现数据迁移。这就是我所做的 # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import migrations def create_basic_user_group(apps, schema_editor): """Forward data migration that create the basic_user group

我正在尝试使用django 1.7本机迁移系统实现数据迁移。这就是我所做的

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations


def create_basic_user_group(apps, schema_editor):
    """Forward data migration that create the basic_user group

    """
    Group = apps.get_model('auth', 'Group')
    Permission = apps.get_model('auth', 'Permission')
    group = Group(name='basic_user')
    group.save()

    perm_codenames = (
        'add_stuff',
        '...',
    )

    # we prefere looping over all these in order to be sure to fetch them all
    perms = [Permission.objects.get(codename=codename)
             for codename in perm_codenames]

    group.permissions.add(*perms)
    group.save()


def remove_basic_user_group(apps, schema_editor):
    """Backward data migration that remove the basic_user group

    """
    group = Group.objects.get(name='basic_user')
    group.delete()


class Migration(migrations.Migration):
    """This migrations automatically create the basic_user group.

    """

    dependencies = [
    ]

    operations = [
        migrations.RunPython(create_basic_user_group, remove_basic_user_group),
    ]
但是当我尝试运行迁移时,我得到一个LookupError异常,告诉我找不到标签为“auth”的应用程序


我如何才能以一种干净的方式创建组,以便也可以在单元测试中使用?

因此,我找到了解决此问题的方法,并获得了以下退出:get_model将仅获取您的模型应用程序。我不确定这是否是一个好的做法,但它对我起了作用

我只是直接调用了模型并进行了更改

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.contrib.auth.models import Group


def create_groups(apps, schema_editor):
    g = Group(name='My New Group')
    g.save()


class Migration(migrations.Migration):

    operations = [
        migrations.RunPython(create_groups)
    ]
然后,只需应用/manage.py migrate即可完成。
我希望这会有帮助。

我已经做了你想做的事。问题是:

  • 和的文档非常清楚:如果要从其他应用访问模型,必须将此应用列为依赖项:

    编写
    RunPython
    函数时,如果该函数使用的模型来自迁移所在应用程序以外的应用程序,则迁移的dependencies属性应包括所涉及的每个应用程序的最新迁移,否则,当您尝试使用
    apps.get_model()
    RunPython
    函数中检索模型时,可能会出现类似以下错误:
    LookupError:No installed app with label'myappname'

    因此,您应该依赖于
    auth
    中的最新迁移

  • 正如您在中提到的,您将遇到一个问题,即您要使用的权限尚未创建。问题在于,权限是由附加到
    post\u migrate
    信号的信号处理程序创建的。因此,在迁移完成之前,与迁移中创建的任何新模型相关联的权限都不可用

    您可以在
    create\u basic\u user\u group
    的开头执行此操作来解决此问题:

    from django.contrib.contenttypes.management import update_contenttypes
    from django.apps import apps as configured_apps
    from django.contrib.auth.management import create_permissions
    
    for app in configured_apps.get_app_configs():
        update_contenttypes(app, interactive=True, verbosity=0)
    
    for app in configured_apps.get_app_configs():
        create_permissions(app, verbosity=0)
    
    这还将为每个模型创建内容类型(也是在迁移之后创建的),请参见下文,了解您为什么应该关注这些

    也许在上面的代码中,你可以比我更具选择性:只更新一些关键应用程序,而不是更新所有应用程序。我没有试着选择。此外,两个循环也可能合并为一个。我还没有试过一个圈

  • 通过搜索
    codename
    可以获得
    权限
    对象,但
    codename
    不保证唯一。两个应用程序可以具有名为
    Stuff
    的模型,因此您可以拥有与两个不同应用程序关联的
    add\u Stuff
    权限。如果发生这种情况,代码将失败。您应该做的是按
    codename
    content\u type
    进行搜索,这两种方法保证在一起是唯一的。一个独特的
    内容类型
    与项目中的每个模型相关联:两个同名但在不同应用中的模型将获得两种不同的内容类型

    这意味着添加对
    contenttypes
    应用程序的依赖项,并使用
    ContentType
    模型:
    ContentType=apps.get_模型(“contenttypes”,“ContentType”)

  • 如中所述,应在处理权限对象之前发送信号
    post_migrate

    但是Django上已经有一个helper函数来发送所需的信号:
    Django.core.management.sql.emit\u post\u migrate\u signal

    在这里,它是这样工作的:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.db import models, migrations
    from django.core.management.sql import emit_post_migrate_signal
    
    
    PERMISSIONS_TO_ADD = [
        'view_my_stuff',
        ...
    ]
    
    
    def create_group(apps, schema_editor):
        # Workarounds a Django bug: https://code.djangoproject.com/ticket/23422
        db_alias = schema_editor.connection.alias
        try:
            emit_post_migrate_signal(2, False, 'default', db_alias)
        except TypeError:  # Django < 1.8
            emit_post_migrate_signal([], 2, False, 'default', db_alias)
    
        Group = apps.get_model('auth', 'Group')
        Permission = apps.get_model('auth', 'Permission')
    
        group, created = Group.objects.get_or_create(name='MyGroup')
        permissions = [Permission.objects.get(codename=i) for i in PERMISSIONS_TO_ADD]
        group.permissions.add(*permissions)
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('auth', '0001_initial'),
            ('myapp', '0002_mymigration'),
        ]
    
        operations = [
            migrations.RunPython(create_group),
        ]
    
    #-*-编码:utf-8-*-
    从未来导入unicode文字
    从django.db导入模型、迁移
    从django.core.management.sql导入发出\u post\u migrate\u信号
    权限添加=[
    “查看我的东西”,
    ...
    ]
    def创建组(应用程序、架构编辑器):
    #解决Django bug的方法:https://code.djangoproject.com/ticket/23422
    db_alias=schema_editor.connection.alias
    尝试:
    发出后迁移信号(2,False,“default”,db\u别名)
    除类型错误外:#Django<1.8
    发出后迁移信号([],2,False,“default”,db\u别名)
    Group=apps.get_model('auth','Group'))
    权限=应用程序。获取模型('auth','Permission'))
    group,created=group.objects.get\u或\u create(name='MyGroup')
    权限=[Permission.objects.get(codename=i)for i in permissions\u TO\u ADD]
    group.permissions.add(*权限)
    类迁移(migrations.Migration):
    依赖项=[
    (‘auth’,‘0001_首字母’),
    ('myapp','0002_mymigration'),
    ]
    操作=[
    RunPython(创建组),
    ]
    
    尝试
    应用程序。注册应用程序模式和/或依赖
    ('auth','group')
    。这是一个随机的建议,因为我自己还在理解注册表的内容。不过,它帮助我解决了一个类似的问题。在django 1.8中,对象管理器可以在迁移期间使用。尤其是现在,您的代码应该可以像此作品一样工作,但您不能向它们添加权限,因为它们是在迁移后创建的。事实上,如果您迁移一个已经存在的数据库,您会认为它是有效的,因为权限对象是在以前的迁移中创建的。但它将在针对新的空数据库的迁移中失败。