Cách di chuyển mô hình giữa hai ứng dụng Django (Django 1.7)


133

Vì vậy, khoảng một năm trước tôi đã bắt đầu một dự án và giống như tất cả các nhà phát triển mới, tôi không thực sự tập trung quá nhiều vào cấu trúc, tuy nhiên bây giờ tôi cùng với Django, nó đã bắt đầu xuất hiện rằng bố cục dự án của tôi chủ yếu là các mô hình của tôi. .

Tôi có các mô hình chủ yếu được tổ chức trong một ứng dụng duy nhất và thực sự hầu hết các mô hình này phải ở trong các ứng dụng riêng của họ, tôi đã thử và giải quyết vấn đề này và di chuyển chúng về phía nam tuy nhiên tôi thấy nó khó khăn và thực sự khó khăn do khóa ngoại.

Tuy nhiên do Django 1.7 và được xây dựng để hỗ trợ cho việc di chuyển, có cách nào tốt hơn để làm điều này bây giờ không?


4
Bạn có thể muốn xem xét thay đổi câu trả lời được chấp nhận.
Babken Vardanyan

Đối với những người sẽ bắt gặp điều này trong tương lai: Django 3.x ở đây và cách tiếp cận chi tiết tại realpython.com/move-django-model/ trộm đã làm việc cho tôi. Tôi đã có nhiều khóa ngoại giữa các mô hình trong ứng dụng cũ và các mô hình trong ứng dụng mới.
pradeep805

Câu trả lời:


16

Tôi đang loại bỏ câu trả lời cũ vì có thể dẫn đến mất dữ liệu. Như ozan đã đề cập , chúng tôi có thể tạo 2 lần di chuyển trong mỗi ứng dụng. Các ý kiến ​​dưới bài viết này đề cập đến câu trả lời cũ của tôi.

Di chuyển đầu tiên để loại bỏ mô hình từ ứng dụng đầu tiên.

$ python manage.py makemigrations old_app --empty

Chỉnh sửa tập tin di chuyển để bao gồm các hoạt động.

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

Di chuyển thứ hai phụ thuộc vào di chuyển đầu tiên và tạo bảng mới trong ứng dụng thứ hai. Sau khi chuyển mã mô hình sang ứng dụng thứ 2

$ python manage.py makemigrations new_app 

và chỉnh sửa tập tin di chuyển đến một cái gì đó như thế này.

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

Tôi có dữ liệu hiện có và rất nhiều dữ liệu mà tôi đơn giản là không thể mất, có thể làm điều đó với điều này?
Sam Buckingham

@KevinChristopherHenry Đã sửa đổi mã. Điều này bảo tồn dữ liệu hiện có.
ChillarAnand

@SamBuckingham Có, bạn có thể thử với mã được sửa đổi để di chuyển mà không làm mất dữ liệu.
ChillarAnand

2
Tôi nghĩ rằng đó sẽ là cách tốt nhất thực sự, cảm ơn bạn vì tất cả những người giúp đỡ nó đã được xuất sắc.
Sam Buckingham

1
IMO đây là một giải pháp sai lầm, giả định cơ bản của việc di chuyển là nếu bạn chạy ./manage.py migratemọi thứ sẽ kết thúc ở trạng thái tốt. Di chuyển giả mạo thủ công là IMO một cách sai lầm.
jb.

341

Điều này có thể được thực hiện khá dễ dàng bằng cách sử dụng migrations.SeparateDatabaseAndState. Về cơ bản, chúng tôi sử dụng một hoạt động cơ sở dữ liệu để đổi tên bảng đồng thời với hai hoạt động trạng thái để xóa mô hình khỏi lịch sử của một ứng dụng và tạo nó trong lịch sử của một ứng dụng khác.

Xóa khỏi ứng dụng cũ

python manage.py makemigrations old_app --empty

Trong quá trình di chuyển:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

Thêm vào ứng dụng mới

Đầu tiên, sao chép mô hình vào model.txt của ứng dụng mới, sau đó:

python manage.py makemigrations new_app

Điều này sẽ tạo ra một di chuyển với một CreateModelhoạt động ngây thơ là hoạt động duy nhất. Gói nó trong một SeparateDatabaseAndStatehoạt động sao cho chúng ta không cố gắng tạo lại bảng. Cũng bao gồm di chuyển trước như một phụ thuộc:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

14
Giải thích thực sự tốt. Đây phải là câu trả lời, với việc đổi tên bảng bạn tránh mất dữ liệu.
Remiz

11
Đây là cách tốt nhất để làm điều đó và nó tốt hơn nhiều so với của tôi. Đã thêm ghi chú ở đầu câu trả lời của tôi.
ChillarAnand

4
Tôi đã làm điều này, nhưng khi tôi chạy "makemigations" trên newapp sau đó, nó sẽ tạo ra một di chuyển AlterModelTable đổi tên nó thành Không có.
Diego Ponciano

4
Tìm thấy một cách để giải quyết vấn đề của tôi dựa trên những hướng dẫn này. Vấn đề phức tạp hơn nếu bạn có các tham chiếu khóa ngoài là các trường bắt buộc. Tôi đã phải thêm một vài bước để di chuyển các tài liệu tham khảo.
Nỗi nhớ.io

14
Do nhiều yêu cầu, tôi đã tạo một câu trả lời chi tiết về việc di chuyển mô hình FK bằng ví dụ GitHub. stackoverflow.com/questions/30601107/ từ
Nỗi nhớ.io

26

Tôi gặp phải vấn đề tương tự. Câu trả lời của Ozan đã giúp tôi rất nhiều nhưng thật không may là không đủ. Quả thực tôi đã có một số ForeignKey liên kết đến mô hình mà tôi muốn di chuyển. Sau một số đau đầu, tôi tìm thấy giải pháp nên quyết định đăng nó để giải quyết thời gian của mọi người.

Bạn cần thêm 2 bước:

  1. Trước khi làm bất cứ điều gì, hãy thay đổi tất cả ForeignKeyliên kết của bạn thànhTheModel thành Integerfield. Sau đó chạypython manage.py makemigrations
  2. Sau khi thực hiện các bước của Ozan, hãy chuyển đổi lại khóa ngoại của bạn: đặt lại ForeignKey(TheModel)thay vì IntegerField(). Sau đó thực hiện di chuyển một lần nữa (python manage.py makemigrations ). Sau đó, bạn có thể di chuyển và nó sẽ hoạt động ( python manage.py migrate)

Hy vọng nó giúp. Tất nhiên kiểm tra nó tại địa phương trước khi thử sản xuất để tránh những bất ngờ xấu :)


8
Còn mối quan hệ ManyToManyField thì sao ??
tomcounsell

1
@tomcounsell bình luận tuyệt vời, tôi sẽ giả sử bằng cách thêm một mô hình cụ thể thông qua chỉ cho mục đích di chuyển. Rất nhiều công việc cần thiết để giữ nguyên dữ liệu ...
Wtower

Vì mối quan hệ nhiều-nhiều thường chỉ là một bảng có hai khóa ngoại, nên theo quan điểm SQL, bạn có thể áp dụng mẹo của câu trả lời này. Nhưng để đạt được điều này chỉ thông qua Django, một cách tiếp cận tôi có thể nghĩ là sẽ đi theo dòng câu trả lời @ozan, ngoại trừ bước đầu tiên là sao chép các bảng liên quan đến mối quan hệ MTM (một phiên bản của các bản sao trong mỗi ứng dụng) , di chuyển tất cả Khóa ngoại sang ứng dụng mới và chỉ sau đó xóa các bản sao trong ứng dụng cũ. Tuyên bố miễn trừ trách nhiệm: Tôi chưa thử nghiệm :)
Arnaud P

15

Tôi đã làm như thế nào (đã thử nghiệm trên Django == 1.8, với postgres, vì vậy có lẽ cũng 1.7)

Tình hình

ứng dụng1.YourModel

nhưng bạn muốn nó đi đến: app2.YourModel

  1. Sao chép YourModel (mã) từ app1 sang app2.
  2. thêm phần này vào app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
  3. $ python Manage.py makemigations app2

  4. Một di chuyển mới (ví dụ 0009_auto_s Something.py) được tạo trong app2 với một câu lệnh di chuyển.CreateModel (), di chuyển câu lệnh này sang di chuyển ban đầu của app2 (ví dụ 0001_initial.py) (nó sẽ giống như nó luôn ở đó). Và bây giờ hãy xóa di chuyển đã tạo = 0009_auto_s Something.py

  5. Giống như bạn hành động, như app2.YourModel luôn ở đó, bây giờ hãy xóa sự tồn tại của app1.YourModel khỏi các lần di chuyển của bạn. Ý nghĩa: nhận xét các câu lệnh CreatModel và mọi điều chỉnh hoặc cơ sở dữ liệu bạn đã sử dụng sau đó.

  6. Và tất nhiên, mọi tham chiếu đến app1.YourModel phải được đổi thành app2.YourModel thông qua dự án của bạn. Ngoài ra, đừng quên rằng tất cả các khóa ngoại có thể có cho app1.YourModel trong quá trình di chuyển phải được đổi thành app2.YourModel

  7. Bây giờ nếu bạn thực hiện di chuyển $ python Manage.txt, không có gì thay đổi, cũng như khi bạn thực hiện các mô hình $ python Manage.py, không có gì mới được phát hiện.

  8. Bây giờ, việc hoàn thiện: xóa Class Meta khỏi app2.YourModel và thực hiện $ python Manage.py makemigations app2 && python Manage.py di chuyển app2 (nếu bạn nhìn vào di chuyển này, bạn sẽ thấy một cái gì đó như thế này :)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),

bảng = Không có nghĩa là nó sẽ lấy tên bảng mặc định, trong trường hợp này sẽ là app2_yourmodel.

  1. Làm, với dữ liệu được lưu.

PS trong quá trình di chuyển, nó sẽ thấy rằng content_type app1.yourmodel đã bị xóa và có thể bị xóa. Bạn có thể nói đồng ý với điều đó nhưng chỉ khi bạn không sử dụng nó. Trong trường hợp bạn phụ thuộc rất nhiều vào nó để có FK cho loại nội dung đó còn nguyên vẹn, đừng trả lời có hoặc không, nhưng hãy truy cập db theo cách thủ công và xóa nội dung app2.yourmodel và đổi tên ứng dụng nội dung1. yourmodel đến app2.yourmodel, và sau đó tiếp tục bằng cách trả lời không.


3
Mặc dù giải pháp này chắc chắn là "hackier" hơn @ ozan và nó chắc chắn cần chỉnh sửa nhiều hơn, nhưng nó hoạt động tốt đối với tôi (và nó ổn khi chỉnh sửa di chuyển - chúng được cho là có thể chỉnh sửa, theo tài liệu).
pgcd

1
Cũng có thể sử dụng app_label = 'app1'tùy chọn meta.
Wtower

Thiên tài! Điều này làm việc rất tốt cho tôi cho các mối quan hệ ForeignKey. Tôi cho rằng điều này cũng sẽ hoạt động cho các trường ManyToMany.
Babken Vardanyan

Tôi đã làm theo các bước của bạn nhưng trường trong một số mô hình thuộc về ứng dụng 1 bao gồm Khóa ngoài có mối quan hệ đệ quy với mô hình (myModel) sẽ được di chuyển. Giống như field1 = models.ForeignKey('app1.myModel').khi tôi di chuyển, tôi nhận được ValueError nói rằngfield1 was declared with a lazy reference to 'app1.myModel' but app 'app1' doesn't provide model 'MyModel'
Deesha

12

Tôi nhận được sự di chuyển mã hóa tay lo lắng (theo yêu cầu của câu trả lời của Ozan ) vì vậy những điều sau đây kết hợp các chiến lược của Ozan và Michael để giảm thiểu lượng mã hóa tay cần thiết:

  1. Trước khi di chuyển bất kỳ mô hình nào, hãy đảm bảo bạn đang làm việc với đường cơ sở sạch bằng cách chạy makemigrations.
  2. Di chuyển mã cho Model từ app1sangapp2
  3. Theo khuyến nghị của @Michael, chúng tôi trỏ mô hình mới vào bảng cơ sở dữ liệu cũ bằng db_tabletùy chọn Meta trên mô hình "mới":

    class Meta:
        db_table = 'app1_yourmodel'
  4. Chạy đi makemigrations. Điều này sẽ tạo ra CreateModeltrong app2DeleteModeltrong app1. Về mặt kỹ thuật, các di chuyển này đề cập đến cùng một bảng và sẽ xóa (bao gồm tất cả dữ liệu) và tạo lại bảng.

  5. Trong thực tế, chúng tôi không muốn (hoặc cần) làm bất cứ điều gì để bàn. Chúng tôi chỉ cần Django để tin rằng sự thay đổi đã được thực hiện. Mỗi câu trả lời của @ Ozan,state_operations lá cờ SeparateDatabaseAndStatethực hiện điều này. Vì vậy, chúng tôi gói tất cả các migrationsmục trong CẢ HAI PHIM DI CHUYỂN với SeparateDatabaseAndState(state_operations=[...]). Ví dụ,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]

    trở thành

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. Bạn cũng cần đảm bảo CreateModeldi chuyển "ảo" mới phụ thuộc vào bất kỳ di chuyển nào thực sự tạo hoặc thay đổi bảng gốc . Ví dụ: nếu các lần di chuyển mới của bạn là app2.migrations.0004_auto_<date>(đối với Create) và app1.migrations.0007_auto_<date>(đối với Delete), điều đơn giản nhất cần làm là:

    • Mở app1.migrations.0007_auto_<date>và sao chép app1phụ thuộc của nó (ví dụ ('app1', '0006...'),). Đây là di chuyển "ngay trước" app1và nên bao gồm các phụ thuộc vào tất cả logic xây dựng mô hình thực tế.
    • Mở app2.migrations.0004_auto_<date> và thêm phụ thuộc mà bạn vừa sao chép vào dependenciesdanh sách của nó .

Nếu bạn có ForeignKey(các) mối quan hệ với mô hình bạn đang di chuyển, điều trên có thể không hoạt động. Điều này xảy ra vì:

  • Phụ thuộc không được tạo tự động cho các ForeignKeythay đổi
  • Chúng tôi không muốn bao gồm các ForeignKeythay đổi trongstate_operations vì vậy chúng tôi cần đảm bảo chúng tách biệt với các hoạt động của bảng.

LƯU Ý: Django 2.2 đã thêm cảnh báo ( models.E028) phá vỡ phương thức này. Bạn có thể làm việc với nómanaged=False nhưng tôi chưa thử.

Tập hợp các hoạt động "tối thiểu" khác nhau tùy theo tình huống, nhưng quy trình sau sẽ hoạt động với hầu hết / tất cả các lần ForeignKeydi chuyển:

  1. SAO CHÉP mô hình từ app1đếnapp2 , đặt db_table, nhưng KHÔNG thay đổi bất kỳ tham chiếu FK nào.
  2. Chạy makemigrationsvà bọc tất cả app2di chuyển trong state_operations(xem ở trên)
    • Như trên, thêm một phụ thuộc vào di chuyển app2 CreateTablemới nhấtapp1
  3. Trỏ tất cả các tham chiếu FK đến mô hình mới. Nếu bạn không sử dụng tham chiếu chuỗi, hãy di chuyển mô hình cũ xuống dưới cùng củamodels.py (KHÔNG loại bỏ nó) để nó không cạnh tranh với lớp đã nhập.
  4. Chạy makemigrationsnhưng KHÔNG bọc bất cứ thứ gì vào state_operations(những thay đổi FK thực sự sẽ xảy ra). Thêm một phụ thuộc trong tất cả các ForeignKeydi chuyển (nghĩa là AlterField) vào CreateTabledi chuyển trongapp2 (bạn sẽ cần danh sách này cho bước tiếp theo để theo dõi chúng). Ví dụ:

    • Tìm di chuyển bao gồm CreateModelví dụapp2.migrations.0002_auto_<date> và sao chép tên của di chuyển đó.
    • Tìm tất cả các di chuyển có ForeignKey cho mô hình đó (ví dụ: bằng cách tìm kiếm app2.YourModelđể tìm các di chuyển như:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • Thêm CreateModeldi chuyển như là một phụ thuộc:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. Loại bỏ các mô hình từ app1

  6. Chạy makemigrationsvà bọcapp1 di chuyển trong state_operations.
    • Thêm một phụ thuộc vào tất cả các lần ForeignKeydi chuyển (nghĩa là AlterField) từ bước trước đó (có thể bao gồm các lần di chuyển trong app1app2).
    • Khi tôi xây dựng các di chuyển này, việc di chuyển DeleteTableđã phụ thuộc vào AlterFielddi chuyển nên tôi không cần phải thực thi thủ công (tức là Altertrước đó Delete).

Tại thời điểm này, Django là tốt để đi. Mô hình mới chỉ ra bảng cũ và sự di cư của Django đã thuyết phục rằng mọi thứ đã được di dời một cách thích hợp. Nhắc nhở lớn (từ câu trả lời của @ Michael) là một cái mới ContentTypeđược tạo ra cho mô hình mới. Nếu bạn liên kết (ví dụ ForeignKey:) với các loại nội dung, bạn sẽ cần tạo một di chuyển để cập nhật ContentTypebảng.

Tôi muốn tự dọn dẹp (tùy chọn Meta và tên bảng) vì vậy tôi đã sử dụng quy trình sau (từ @Michael):

  1. Xóa db_tablemục nhập Meta
  2. Chạy makemigrationslại để tạo đổi tên cơ sở dữ liệu
  3. Chỉnh sửa di chuyển cuối cùng này và đảm bảo nó phụ thuộc vào DeleteTabledi chuyển. Có vẻ như nó không cần thiết vì Deletenó hoàn toàn hợp lý, nhưng tôi đã gặp phải lỗi (ví dụ: app1_yourmodelkhông tồn tại) nếu tôi không.

Điều này làm việc hoàn hảo, cảm ơn bạn! Tôi không nghĩ rằng việc chỉnh sửa lần di chuyển cuối cùng là vấn đề vì đây là phần cuối của cây phụ thuộc.
James Meakin

1
Câu trả lời tốt! Tôi nghĩ rằng bạn cần phải thêm dấu ngoặc đơn đóng cho di chuyển.SeparateDatabaseAndState, phải không?
atm

Điều này làm việc cho tôi. Tôi cũng không chỉnh sửa lần di chuyển cuối cùng (bước 3, dòng cuối cùng của toàn bộ câu trả lời) như @JamesMeakin và nó vẫn hoạt động tốt
Megawatt

trong kịch bản thứ hai, một lỗi với FK, bước thứ hai đã thất bại với tôi với một lỗi có ý nghĩa:table_name: (models.E028) db_table 'table_name' is used by multiple models: app1.Model, app2.Model.
Mihai Zamfir

Tôi đã sử dụng thủ tục một vài lần. Nếu bạn so sánh tài liệu cho 2.2 ( docs.djangoproject.com/en/2.2/ref/checks ) và 2.1 ( docs.djangoproject.com/en/2.1/ref/checks ), bạn có thể thấy nó đã được thêm vào 2.2. Có thể có thể làm việc xung quanh managed=Falsenhưng tôi không có nơi nào để kiểm tra.
claytond

1

Một cách thay thế hacky khác nếu dữ liệu không lớn hoặc quá phức tạp, nhưng vẫn quan trọng để duy trì, là:

  • Nhận đồ đạc dữ liệu bằng cách sử dụng Manage.txt dumpdata
  • Tiến hành thay đổi mô hình và di chuyển đúng cách, không liên quan đến các thay đổi
  • Toàn cầu thay thế các đồ đạc từ mô hình cũ và tên ứng dụng sang mới
  • Tải dữ liệu bằng cách sử dụng Manage.txt loaddata

1

Sao chép từ câu trả lời của tôi tại https://stackoverflow.com/a/47392970/8971048

Trong trường hợp bạn cần di chuyển mô hình và bạn không có quyền truy cập vào ứng dụng nữa (hoặc bạn không muốn truy cập), bạn có thể tạo một Hoạt động mới và xem xét để tạo một mô hình mới chỉ khi mô hình di chuyển không hiện hữu.

Trong ví dụ này, tôi chuyển 'MyModel' từ old_app sang myapp.

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

Vui lòng không thêm cùng một câu trả lời cho nhiều câu hỏi. Trả lời câu hỏi hay nhất và đánh dấu phần còn lại là trùng lặp. Xem Có được chấp nhận để thêm một câu trả lời trùng lặp cho một số câu hỏi không?
Petter Friberg

0

Điều này đã được kiểm tra đại khái, vì vậy đừng quên sao lưu DB của bạn !!!

Ví dụ: có hai ứng dụng: src_appdst_app, chúng tôi muốn chuyển mô hình MoveMetừ src_appsang dst_app.

Tạo di chuyển trống cho cả hai ứng dụng:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

Giả sử, di cư mới là XXX1_src_app_newXXX1_dst_app_new, di cư hàng đầu là XXX0_src_app_oldXXX0_dst_app_old.

Thêm một hoạt động đổi tên bảng cho MoveMemô hình và đổi tên app_label của nó trong ProjectState thành XXX1_dst_app_new. Đừng quên thêm phụ thuộc vào XXX0_src_app_olddi chuyển. XXX1_dst_app_newDi chuyển kết quả là:

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

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

Thêm sự phụ thuộc vào XXX1_dst_app_newtới XXX1_src_app_new. XXX1_src_app_newlà di chuyển không cần thiết để đảm bảo rằng các src_appdi chuyển trong tương lai sẽ được thực hiện sau đó XXX1_dst_app_new.

Di chuyển MoveMetừ src_app/models.pyđến dst_app/models.py. Sau đó chạy:

python manage.py migrate

Đó là tất cả!


Lưu ý rằng mã này có lẽ chỉ hữu ích cho django 1.7. Thử điều này trong django 2.0 sẽ không hoạt động. Điều này cũng có nghĩa là việc sử dụng cơ chế này để di chuyển các mô hình sẽ thêm chi phí bảo trì để nâng cấp phiên bản django của bạn.
Paul trong 't Hout

0

Bạn có thể thử những điều sau (chưa được kiểm tra):

  1. chuyển mô hình từ src_appsangdest_app
  2. di cư dest_app; đảm bảo di chuyển lược đồ phụ thuộc vào src_appdi chuyển mới nhất ( https://docs.djangoproject.com/en/dev/topics/migations/#migration-files )
  3. thêm di chuyển dữ liệu vào dest_app, sao chép tất cả dữ liệu từsrc_app
  4. di cư src_app; đảm bảo di chuyển lược đồ phụ thuộc vào di chuyển (dữ liệu) mới nhất của dest_app- đó là: di chuyển của bước 3

Lưu ý rằng bạn sẽ sao chép toàn bộ bảng, thay vì di chuyển bảng, nhưng theo cách đó, cả hai ứng dụng không phải chạm vào bảng thuộc về ứng dụng khác, điều mà tôi nghĩ là quan trọng hơn.


0

Hãy nói rằng bạn đang chuyển mô hình TheModel từ app_a sang app_b.

Một giải pháp thay thế là thay đổi các di chuyển hiện có bằng tay. Ý tưởng là mỗi khi bạn thấy một thao tác thay đổi TheModel trong quá trình di chuyển của app_a, bạn sao chép thao tác đó vào cuối di chuyển ban đầu của app_b. Và mỗi khi bạn thấy một tham chiếu 'app_a .Model' trong quá trình di chuyển của app_a, bạn thay đổi nó thành 'app_b .Model'.

Tôi vừa làm điều này cho một dự án hiện có, nơi tôi muốn trích xuất một mô hình nhất định sang một ứng dụng có thể tái sử dụng. Thủ tục diễn ra suôn sẻ. Tôi đoán mọi thứ sẽ khó khăn hơn nhiều nếu có các tài liệu tham khảo từ app_b đến app_a. Ngoài ra, tôi đã có một Meta.db_table được xác định thủ công cho mô hình của mình có thể giúp ích.

Đáng chú ý là bạn sẽ kết thúc với lịch sử di chuyển đã thay đổi. Điều này không thành vấn đề, ngay cả khi bạn có cơ sở dữ liệu với các lần di chuyển ban đầu được áp dụng. Nếu cả hai lần di chuyển ban đầu và viết lại kết thúc với cùng một lược đồ cơ sở dữ liệu, thì việc viết lại như vậy sẽ ổn.


0
  1. thay đổi tên của các mô hình cũ thành 'model_name_old'
  2. tạm thời
  3. tạo các mô hình mới có tên 'model_name_new' với các mối quan hệ giống hệt nhau trên các mô hình liên quan (ví dụ: mô hình người dùng hiện có user.blog_old và user.blog_new)
  4. tạm thời
  5. viết một di chuyển tùy chỉnh di chuyển tất cả dữ liệu vào các bảng mô hình mới
  6. kiểm tra địa ngục của những lần di chuyển này bằng cách so sánh các bản sao lưu với các bản sao db mới trước và sau khi chạy di chuyển
  7. Khi tất cả đã thỏa đáng, xóa các mô hình cũ
  8. tạm thời
  9. thay đổi các mô hình mới thành tên chính xác 'model_name_new' -> 'model_name'
  10. kiểm tra toàn bộ di chuyển trên một máy chủ dàn
  11. đưa trang web sản xuất của bạn xuống trong vài phút để chạy tất cả các lần di chuyển mà không có người dùng can thiệp

Làm điều này riêng cho từng mô hình cần phải được di chuyển. Tôi không đề nghị làm những gì câu trả lời khác nói bằng cách thay đổi số nguyên và quay lại khóa ngoại Có khả năng các khóa ngoại mới sẽ khác và các hàng có thể có ID khác nhau sau khi di chuyển và tôi không muốn gặp rủi ro của id không khớp khi chuyển về khóa ngoại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.