Sử dụng nhiều cơ sở dữ liệu trong Django chỉ với một bảng dj dj_migations


11

Đối với một dự án trong Django tôi phải sử dụng hai cơ sở dữ liệu: mặc địnhtừ xa . Tôi đã tạo ra routers.pyvà mọi thứ hoạt động tốt.

Có một yêu cầu để tạo một bảng trên cơ sở dữ liệu từ xa và tôi đã tạo di chuyển, chạy nó và bảng django_migrationsđã được tạo. Tôi muốn chỉ có một bảng django_migrations, trong cơ sở dữ liệu mặc định.

Phần có liên quan routers.pylà ở đây:

class MyRouter(object):
     # ...
     def allow_migrate(self, db, app_label, model_name=None, **hints):
         if app_label == 'my_app':
             return db == 'remote'
         return None

Tôi chạy di chuyển như thế này:

python manage.py migrate my_app --database=remote

Bây giờ khi tôi làm:

python manage.py runserver

Tôi nhận được cảnh báo sau:

Bạn có 1 di chuyển chưa được áp dụng. Dự án của bạn có thể không hoạt động chính xác cho đến khi bạn áp dụng di chuyển cho (các) ứng dụng: my_app.
Chạy 'python Manage.py di chuyển' để áp dụng chúng.

Các bảng cho my_appđược tạo ra trong remotecơ sở dữ liệu, và ở django_migrationsbên trong remotecơ sở dữ liệu di cư được đánh dấu là áp dụng.

EDIT:
Làm thế nào để buộc Django chỉ sử dụng một bảng django_migrations, nhưng vẫn áp dụng các di chuyển vào các cơ sở dữ liệu khác nhau?

Làm thế nào để áp dụng các di chuyển trong các cơ sở dữ liệu khác nhau để không có cảnh báo nào được nêu ra?


1
đối với các ứng dụng khác không phải là 'my_app', allow_migrate sẽ không trả về. Có lẽ bạn muốn làm một kiểm tra khác ở đó? Từ những gì tôi hiểu từ bộ định tuyến của bạn, 'my_app' sử dụng cơ sở dữ liệu 'từ xa' và tất cả các ứng dụng khác sẽ sử dụng cơ sở dữ liệu 'mặc định'?
Martin Taleski

@cezar Bạn yêu cầu gần như không thể. Để có django_migrationsbảng chia sẻ , sẽ cần phải phân biệt giữa các hàng với di chuyển cho defaultremotedb. Điều này là khá sâu sắc trong nội bộ django. Tôi thậm chí sẽ mạo hiểm nói rằng nó sẽ yêu cầu viết lại mã di chuyển.
Kamil Niski

@KamilNiski cảm ơn bạn đã chia sẻ suy nghĩ của bạn. Tôi sẽ điều chỉnh lại câu hỏi.
cezar

Vấn đề này có thể có liên quan.
Kevin Christopher Henry

Câu trả lời:


2

Nhờ những bình luận về câu hỏi của tôi, tôi đã thực hiện một số nghiên cứu và đưa ra những phát hiện sau đây.

Sử dụng nhiều cơ sở dữ liệu dẫn đến việc tạo bảng django_migrationskhi di chuyển được sử dụng. Không có tùy chọn để ghi lại các lần di chuyển chỉ trong một bảng django_migrations, như nhận xét từ Kamil Niski giải thích. Điều này là rõ ràng sau khi đọc các tập tin django/db/migrations/recorder.py.

Tôi sẽ minh họa một ví dụ với một dự án foovà một ứng dụng barbên trong dự án. Ứng dụng barnày chỉ có một mô hình Baz.

Chúng tôi tạo ra dự án:

django-admin startproject foo

Bây giờ chúng ta có những nội dung này trong thư mục dự án chính:

- foo
- manage.py

Tôi có thói quen nhóm tất cả các ứng dụng trong thư mục dự án:

mkdir foo/bar
python manage.py bar foo/bar

Trong tệp foo/settings.pychúng tôi điều chỉnh cài đặt để sử dụng hai cơ sở dữ liệu khác nhau, cho mục đích của ví dụ này, chúng tôi sử dụng sqlite3:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db1.sqlite3'),
    },
    'remote': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
    }
}

Bây giờ chúng tôi chạy di chuyển:

python manage.py migrate --database=default

Điều này chạy tất cả các di chuyển, phần --database=defaultlà tùy chọn, vì nếu không chỉ định Django sử dụng cơ sở dữ liệu mặc định.

Các thao tác để thực hiện: 
  Áp dụng tất cả các lần di chuyển: admin, auth, contenttypes, session
 Chạy di chuyển:
  Áp dụng nội dung.0001_initial ... OK
  Áp dụng auth.0001_initial ... OK
  Áp dụng admin.0001_initial ... OK
  Áp dụng admin.0002_logentry_remove_auto_add ... OK
  Áp dụng admin.0003_logentry_add_action_flag_choices ... OK
  Áp dụng contenttypes.0002_remove_content_type_name ... OK
  Áp dụng auth.0002_alter_ allow_name_max_length ... OK
  Áp dụng auth.0003_alter_user_email_max_length ... OK
  Áp dụng auth.0004_alter_user_username_opts ... OK
  Áp dụng auth.0005_alter_user_last_login_null ... OK
  Áp dụng auth.0006_Vquire_contenttypes_0002 ... OK
  Áp dụng auth.0007_alter_validators_add_error_messages ... OK
  Áp dụng auth.0008_alter_user_username_max_length ... OK
  Áp dụng auth.0009_alter_user_last_name_max_length ... OK
  Áp dụng auth.0010_alter_group_name_max_length ... OK
  Áp dụng auth.0011_update_proxy_permissions ... OK
  Áp dụng phiên.0001_initial ... OK

Django đã áp dụng tất cả các di chuyển vào cơ sở dữ liệu mặc định:

1 nội dung 0001_initial 2019-11-13 16: 51: 04.767382
2 auth 0001_initial 2019-11-13 16: 51: 04.792245
3 quản trị viên 0001_initial 2019-11-13 16: 51: 04.827454
4 quản trị viên 0002_logentr 2019-11-13 16: 51: 04.846627
5 quản trị viên 0003_logentr 2019-11-13 16: 51: 04.864458
6 nội dung 0002_remove_ 2019-11-13 16: 51: 04.892220
7 auth 0002_alter_p 2019-11-13 16: 51: 04.906449
8 auth 0003_alter_u 2019-11-13 16: 51: 04.923902
9 auth 0004_alter_u 2019-11-13 16: 51: 04.941707
10 auth 0005_alter_u 2019-11-13 16: 51: 04.958371
11 auth 0006_Vquire 2019-11-13 16: 51: 04.965527
12 auth 0007_alter_v 2019-11-13 16: 51: 04.981532
13 auth 0008_alter_u 2019-11-13 16: 51: 05.004149
14 auth 0009_alter_u 2019-11-13 16: 51: 05.019705
15 auth 0010_alter_g 2019-11-13 16: 51: 05.037023
16 auth 0011_update_ 2019-11-13 16: 51: 05.054449
17 phiên 0001_initial 2019-11-13 16: 51: 05.063868

Bây giờ chúng ta tạo mô hình Baz:

models.py:

from django.db import models

class Baz(models.Model):
    name = models.CharField(max_length=255, unique=True)

đăng ký ứng dụng barvào INSTALLED_APPS( foo/settings.py) và tạo chủ đề:

python manage.py makemigrations bar

Trước khi chúng tôi chạy di chuyển, chúng tôi tạo routers.pybên trong barứng dụng:

lớp BarRouter (đối tượng):
    def db_for_read (tự, mô hình, ** gợi ý):
        if model._meta.app_label == 'bar':
            trả lại 'từ xa'
        trở về Không

    def db_for_write (tự, mô hình, ** gợi ý):
        if model._meta.app_label == 'bar':
            trả lại 'từ xa'
        trở về Không

    def allow_relation (self, obj1, obj2, ** gợi ý):
        trở về Không

    def allow_migrate (self, db, app_label, model_name = Không, ** gợi ý):
        if app_label == 'bar':
            trả về db ​​== 'từ xa'
        nếu db == 'từ xa':
            trả về sai
        trở về Không

và đăng ký nó trong foo/settings.py:

DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']

Bây giờ cách tiếp cận ngây thơ sẽ là chạy các di chuyển barvào remotecơ sở dữ liệu:

python manage.py migrate bar --database=remote
Các thao tác để thực hiện: 
  Áp dụng tất cả các lần di chuyển: thanh
 Chạy di chuyển:
  Áp dụng thanh.0001_initial ... OK

Việc di chuyển đã được áp dụng cho remotecơ sở dữ liệu:

1 thanh 0001_initial 2019-11-13 17: 32: 39.701784

Khi chúng tôi chạy:

python manage.py runserver

cảnh báo sau đây sẽ được nêu ra:

Bạn có 1 di chuyển chưa được áp dụng. Dự án của bạn có thể không hoạt động đúng cho đến khi bạn áp dụng chuyển đổi cho (các) ứng dụng: thanh.
Chạy 'python Manage.py di chuyển' để áp dụng chúng.

Tất cả mọi thứ dường như làm việc tốt mặc dù. Tuy nhiên, nó không thỏa mãn khi có cảnh báo này.

Cách thích hợp sẽ là chạy tất cả các di chuyển cho mỗi cơ sở dữ liệu như được đề xuất trong câu trả lời này .

Nó sẽ trông như thế này:

python manage.py migrate --database=default
python manage.py migrate --database=remote

và sau khi tạo các chuyển đổi cho bar:

python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote

Bộ định tuyến sẽ quan tâm rằng bảng bar_bazchỉ được tạo trong remotecơ sở dữ liệu, nhưng Django sẽ đánh dấu các lần di chuyển như được áp dụng trong cả hai cơ sở dữ liệu. Ngoài ra các bảng cho auth, admin, sessions, vv sẽ được tạo ra duy nhất trong defaultcơ sở dữ liệu, theo quy định tại routers.py. Bảng django_migrationstrong remotecơ sở dữ liệu cũng sẽ có các bản ghi cho các lần di chuyển này.

Đó là một bài đọc dài, nhưng tôi hy vọng nó làm sáng tỏ điều này, theo ý kiến ​​của tôi, không giải thích cặn kẽ vấn đề trong tài liệu chính thức .

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.