Django 1.7数据迁移和用户组 [英] Django 1.7 datamigration and user groups

查看:66
本文介绍了Django 1.7数据迁移和用户组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to implement a datamigration using django 1.7 native migration system. Here is what I've done.

# -*- 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"的应用.

But when I try to run the migration, I got a LookupError exception telling me that no app with label 'auth' could be found.

如何以一种可以在单元测试中使用的干净方式创建组?

How can I create my groups in a clean way that could also be used in unit tests ?

推荐答案

我已经完成了您想做的事情.问题是:

I've done what you are trying to do. The problems are:

  1. 1.7 和 1.8 非常清楚:如果要从另一个应用程序访问模型,则必须将此应用程序列为依赖项:

  1. The documentation for 1.7 and 1.8 is quite clear: If you want to access a model from another app, you must list this app as a dependency:

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

When writing a RunPython function that uses models from apps other than the one in which the migration is located, the migration’s dependencies attribute should include the latest migration of each app that is involved, otherwise you may get an error similar to: LookupError: No installed app with label 'myappname' when you try to retrieve the model in the RunPython function using apps.get_model().

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

So you should have a dependency on the latest migration in auth.

如您在评论中所述您将遇到一个问题,即尚未创建要使用的权限.问题是权限是由附加到post_migrate信号的信号处理程序创建的.因此,与迁移中创建的任何 new 模型相关的权限在迁移完成 之前不可用.

As you mentioned in a comment you will run into an issue whereby the permissions you want to use are not created yet. The problem is that the permissions are created by signal handler attached to the post_migrate signal. So the permissions associated with any new model created in a migration are not available until the migration is finished.

您可以通过在create_basic_user_group开始时执行此操作来解决此问题:

You can fix this by doing this at the start of 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)

这还将为每个模型创建内容类型(也在迁移后 创建),请参见下文了解为什么要对此进行关注.

This will also create the content types for each model (which are also created after the migration), see below as to why you should care about that.

也许您可能比上面的代码更具选择性:仅更新一些关键应用程序而不是更新所有应用程序.我没有试图有选择性.同样,两个循环都可能合并为一个.我还没有尝试过一个循环.

Perhaps you could be more selective than I am in the code above: update just some key apps rather than update all apps. I've not tried to be selective. Also, it is possible that both loop could be merged into one. I've not tried it with a single loop.

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

You get your Permission objects by searching by codename but codename is not guaranteed to be unique. Two apps can have models called Stuff and so you could have an add_stuff permission associated with two different apps. If this happens, your code will fail. What you should do is search by codename and content_type, which are guaranteed to be unique together. A unique content_type is associated with each model in the project: two models with the same name but in different apps will get two different content types.

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

This means adding a dependency on the contenttypes app, and using the ContentType model: ContentType = apps.get_model("contenttypes", "ContentType").

这篇关于Django 1.7数据迁移和用户组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆