2014-10-01 83 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), 
    ]