2014-10-01 84 views
7

我正在尝试使用django 1.7本机迁移系统实现数据迁移。这是我所做的。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例外告诉我,与标签“权威性”没有应用程序可以被发现。

如何在单元测试中以干净的方式创建我的组?

+1

尝试'app.get_registered_model'和/或依赖于'( 'auth','group')'。 这是一种随机的建议,因为我仍然在自己理解注册表的过程。它帮助我解决了类似的问题。 – 2014-10-09 09:38:36

+1

在django 1.8中,对象管理者可以在迁移过程中使用。特别是现在您的代码应该按原样工作 – 2015-05-19 13:47:08

回答

1

所以,我想出了如何解决这个问题,我得到了以下退出: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迁移完成。 我希望它有帮助。

+1

这可以工作,但您无法为其添加权限,因为它们是在迁移后信号上创建的。事实上,如果你迁移一个已经存在的数据库,你会认为它起作用,因为在先前的迁移中已经创建了许可对象。但是它将在针对新的空数据库迁移时失败。 – Egg 2014-12-11 09:38:55

5

我已经完成了你正在尝试做的事情。这些问题是:

  1. 1.71.8的文档是很清楚的:如果你想从另一个应用程序访问的模式,你必须列出该应用程序的依赖性:

    当编写一个RunPython函数使用除迁移所在的应用程序之外的其他应用程序的模型,迁移的依赖项属性应该包含所涉及的每个应用程序的最新迁移,否则在尝试检索时会出现类似于以下内容的错误:LookupError: No installed app with label 'myappname'使用01的RunPython函数模型。

    因此,您应该对auth中的最新迁移有依赖性。

  2. 正如您在comment中提到的那样,您将遇到一个问题,即您要使用的权限尚未创建。问题是权限是通过连接到post_migrate信号的信号处理程序创建的。因此,迁移过程中创建的任何新型模型的权限在迁移为完成之前不可用。

    您可以通过在create_basic_user_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) 
    

    这也将为每个模型的内容类型(这是迁移之后也创造),见下文为为什么你应该关心这一点。

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

  3. 您通过codename搜索得到您的Permission对象,但codename不保证是唯一的。两个应用程序可以有称为Stuff的模型,因此您可以拥有与两个不同应用程序相关的add_stuff权限。如果发生这种情况,您的代码将失败。你应该做的是通过codenamecontent_type进行搜索,这些保证是唯一的。独特的content_type与项目中的每个模型相关联:具有相同名称但具有不同应用程序的两个模型将获得两种不同的内容类型。

    这意味着要添加对contenttypes应用程序的依赖关系,并使用ContentType型号:ContentType = apps.get_model("contenttypes", "ContentType")

1

https://code.djangoproject.com/ticket/23422说,信号post_migrate应该处理的权限对象之前被发送。

但有一个辅助功能已经在Django的,以发送所需的信号:django.core.management.sql.emit_post_migrate_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), 
    ]