2012-11-22 1 views
0

자가 제작 (사용 가능한 플러그인 방법에 가깝습니다) 멀티 테넌트 구현을 사용하는 Django 앱에서 남쪽 (예 : 간단한 add_column)을 실행하고 싶습니다 모든 스키마에 적용될 수 있습니다. 구성이 매우 가까이 this one에 가깝습니다.Django가 멀티 테넌트 DB에서 마이그레이션을 실행 중입니다

가능한 경우 모든 순수 SQL 쿼리를 건너 뛰고 싶습니다. 내가 ORM에서 스키마 이름의 목록을 제대로 얻을 수 있지만, 내가 어떻게 든 propre 방식으로 다양한 스키마에서 테이블에 액세스 할 가능성이 있는지 궁금해.

나는 어떤 수준에서 매개 변수를 통해 DB_HOST와 DB_SCHEMA를 변경할 수있는 고리가 있지만, 남쪽의 전달 방법으로는 이런 방식으로 정상적으로 순환 할 수 없다고 생각합니다.

이 질문은 상당히 높은 수준이지만, 누군가가 같은 종류의 질문에 직면해야하는지 궁금해하며 그것을 처리 할 수있는 영리한 방법이 있는지 궁금합니다.

감사합니다, 매트

답변

0

미세 아니라 많은 사람들이 경험하거나이 꽤 특정 문제에 관심을 것 같다. 나는 여기 저기에 어떤 것을 시험해 보았고, 나는 또한 몇몇 점을 이해하는 데 도움이 된 사우스 메일 링리스트의 지원을 받았다.

나는 한국의 schemamigration를 통해 자동 생성 아주 일반적인 마이그레이션 파일이 있습니다

기본적으로,이 구현 된 솔루션은 다음과 같다. 그러나 테이블 이름을 add_columndelete_column에서 schema.table_name으로 변경했습니다. 멀티 테넌트 미들웨어를 가져 와서 스키마를 제공합니다.

공용 스키마에 대해 스키마가 실행되지 않는 경우에만 마이그레이션이 적용됩니다. 실제로 독립형으로 실행되거나 데이터베이스와 스키마 kwargs로만 실행되는 것이 아니라 새로운 django 명령 인 마이그레이션 실행기에서 실행됩니다.

러너는 안타깝게도 매번 미들웨어를 통과하기 위해 외부로 마이그레이션을 호출해야합니다. 또 다른 트릭은 우리가 이주의 이전 상태를 가져야 만한다는 것입니다. 위조 각 입주자 이전 후 남쪽으로 이전 상태로 가짜입니다. 남쪽의 메일 링리스트에 게시 된

from subprocess import call 
import os 
from django.core.management.base import BaseCommand  
from south.models import MigrationHistory 
from myapp.models import MyModel 

class Command(BaseCommand): 

    def handle(self, *args, **options): 
     #the only allowed arg is the prefix version and it should have a length of 4 (i.e. 0002) 
     applied = MigrationHistory.objects.filter(app_name='myapp').latest('applied') 
     current_version = applied.migration[:4] 
     call_args = ['python', os.path.join('bin', 'manage.py'), 'migrate', 'myorderbird.app.backups'] 
     if len(args) == 1 and len(args[0]) == 4: 
      call_args.append(args[0]) 

     obje_call_args = None 
     for obje in MyModel.objects.all(): 
      if obje.schema_exists: 
       # fake the migration of the previous venue back to the current version 
       if obje_call_args: 
        obje_call_args = obje_call_args[:4] + [current_version, '--fake'] + obje_call_args[len(obje_call_args)-3:] 
        call(obje_call_args) 
       # migrate the venue in the loop 
       obje_call_args = list(call_args) 
       obje_call_args.extend(['--database={}'.format(obje.db), '--schema={}'.format(obje.schema)]) 
       call(venue_call_args) 
1

이이 솔루션의 개요입니다 :

여기 내 코드 조각입니다. 문구로 표시된 질문은 목록에 게시 된 것과 약간 다릅니다. 모든 테넌트간에 공유되는 "공통"테이블이 별도의 스키마에 있음을 언급했습니다. Rmatt 자신의 대답은 이것을 공개 스키마라고합니다.

내 솔루션의 기본 아이디어 : 스키마의 각 데이터베이스 (스키마)에 대한 마이그레이션 기록을 저장하십시오. 이를 위해서는 데이터베이스와 장고 트릭을 사용해야합니다.

공용 스키마에서 앱 마이그레이션에 대한 내역 레코드는 공개 스키마에 저장되지만 임차인 응용 프로그램 마이그레이션 기록은 입주자 스키마에 저장되므로 마이그레이션 기록 테이블을 효과적으로 관리 할 수 ​​있습니다.장고는 실제로 이런 종류의 샤딩을 지원하지 않습니다. 인스턴스 콘텐츠로 쓰기를 설정하기는 쉽지만 읽기를 설정하는 방법은 없습니다.

따라서 퍼블릭 및 테넌트 스키마의 테이블 인 south_migrationhistory의 유니언 인 south_migrationhistory이라는 하나의 뷰가 포함 된 "테넌트 도우미"스키마를 세입자별로 만들 것을 제안했습니다. 그런 다음에 지시 사우스 MigrationHistory 모델 데이터베이스 라우터를 설정 님의 공공 및 세입자 도식 세입자 헬퍼 스키마에서 항상 읽어

  • 쓰기 공용 또는 임차인 스키마에

    • syncdb, 이 앱에 따르면 마이그레이션은 다음과 같습니다.

    결과를 통해 테넌트 앱 마이그레이션에서 공개 앱 마이그레이션으로의 종속성을 적절하게 처리 할 수 ​​있습니다. 그리고 앞으로 나아갈 마이 그 레이션을 할 필요가 없다는 의미입니다. migrate --all (또는 syncdb --migrate) 명령에 대한 루프입니다. 역방향 마이그레이션을 위장 할 필요가 없습니다. 공용 스키마의 마이그레이션은 루프의 첫 번째 테넌트에 대한 마이그레이션으로 실행되며 다른 모든 테넌트는이를 보게됩니다.

    나중에 생각해 보면, 테넌트 스키마에서 south_migrationhistory 테이블의 이름을 바꾸고 쿼리 할 때 위에서 언급 한 공용체를 반환하는 스키마에 해당 이름의 뷰를 설치하여 도우미 스키마 없이도이 작업을 수행 할 수 있습니다 이름이 바뀐 테이블에 쓰는 대신 "삽입 대신"트리거가 있습니다.