ใช้หลายฐานข้อมูลใน Django ด้วยตารางเดียว“ django_migrations”


11

สำหรับโครงการใน Django ฉันต้องใช้สองฐานข้อมูล: เริ่มต้นและระยะไกล ฉันได้สร้างขึ้นrouters.pyและทุกอย่างทำงานได้ดี

มีความต้องการที่จะสร้างตารางในฐานข้อมูลระยะไกลเป็นและฉันสร้างการโยกย้ายรันและตารางdjango_migrationsที่ถูกสร้างขึ้น ฉันต้องการมีเพียงหนึ่งตารางdjango_migrationsในฐานข้อมูลเริ่มต้น

ส่วนที่เกี่ยวข้องrouters.pyอยู่ที่นี่:

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

ฉันใช้การย้ายข้อมูลแบบนี้:

python manage.py migrate my_app --database=remote

ตอนนี้เมื่อฉัน:

python manage.py runserver

ฉันได้รับคำเตือนต่อไปนี้:

คุณมีการโยกย้ายที่ยังไม่ได้ใช้ 1 รายการ โครงการของคุณอาจทำงานไม่ถูกต้องจนกว่าคุณจะใช้การย้ายข้อมูลสำหรับแอป: my_app
เรียกใช้ 'python Manage.py โยกย้าย' เพื่อใช้

ตารางสำหรับmy_appถูกสร้างขึ้นในremoteฐานข้อมูลและdjango_migrationsภายในremoteฐานข้อมูลจะมีการทำเครื่องหมายการย้ายข้อมูลเป็นใช้

แก้ไข:
วิธีการบังคับให้ Django ใช้เพียงหนึ่งตารางdjango_migrationsแต่ยังคงใช้การโยกย้ายในฐานข้อมูลที่แตกต่างกันอย่างไร

วิธีการใช้การย้ายข้อมูลในฐานข้อมูลต่าง ๆ เพื่อไม่ให้มีการเตือนใดขึ้น


1
สำหรับแอปอื่น ๆ ที่ไม่ใช่ 'my_app', allow_migrate กำลังส่งคืน None บางทีคุณอาจต้องการตรวจสอบอีกครั้งที่นั่น? จากสิ่งที่ฉันเข้าใจจากเราเตอร์ของคุณ 'my_app' ใช้ฐานข้อมูล 'remote' และแอพอื่น ๆ ทั้งหมดจะใช้ฐานข้อมูล 'default'
Martin Taleski

@cezar คุณขอเป็นไปไม่ได้เกือบ เพื่อให้มีdjango_migrationsตารางที่ใช้ร่วมกันจะต้องแยกความแตกต่างระหว่างแถวที่มีการย้ายข้อมูลสำหรับdefaultและremotedb มันค่อนข้างลึกลงไปใน django internals ฉันยังมีความเสี่ยงที่ระบุว่าจะต้องมีการเขียนรหัสการโยกย้ายครั้งใหญ่อีกครั้ง
Kamil Niski

@KamilNiski ขอบคุณสำหรับการแบ่งปันความคิดของคุณ ฉันจะตั้งคำถามใหม่
cezar

ปัญหานี้อาจเกี่ยวข้อง
Kevin Christopher Henry

คำตอบ:


2

ขอบคุณความคิดเห็นในคำถามของฉันฉันได้ทำการวิจัยและมาพร้อมกับการค้นพบดังต่อไปนี้

การใช้ฐานข้อมูลหลายรายการทำให้เกิดการสร้างตารางdjango_migrationsเมื่อมีการใช้การย้ายข้อมูล ไม่มีตัวเลือกในการบันทึกการย้ายข้อมูลในหนึ่งตารางdjango_migrationsเท่านั้นเนื่องจากความคิดเห็นจากKamil Niskiอธิบาย django/db/migrations/recorder.pyนี้เป็นที่ชัดเจนหลังจากที่ได้อ่านไฟล์

ฉันจะแสดงตัวอย่างของโครงการfooและแอพbarในโครงการ แอปพลิเคมีเพียงหนึ่งรูปแบบbarBaz

เราสร้างโครงการ:

django-admin startproject foo

ตอนนี้เรามีเนื้อหาเหล่านี้อยู่ในไดเรกทอรีโครงการหลัก:

- foo
- manage.py

ฉันมีนิสัยในการจัดกลุ่มแอพทั้งหมดในไดเรกทอรีโครงการ:

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

ในไฟล์foo/settings.pyเราปรับการตั้งค่าเพื่อใช้สองฐานข้อมูลที่แตกต่างกันตามวัตถุประสงค์ของตัวอย่างนี้เราใช้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'),
    }
}

ตอนนี้เราเรียกใช้การย้ายข้อมูล:

python manage.py migrate --database=default

สิ่งนี้จะทำการโยกย้ายทั้งหมดส่วน--database=defaultนี้เป็นทางเลือกเพราะหากไม่ได้ระบุ Django จะใช้ฐานข้อมูลเริ่มต้น

การดำเนินงานในการดำเนินการ: 
  สมัครโยกย้ายทั้งหมด:ผู้ดูแลระบบรับรองความถูกต้อง, CONTENTTYPES เซสชัน
 เล่นโยกย้าย:
  กำลังใช้ contenttypes.0001_initial ... ตกลง
  ใช้ auth.0001_initial ... ตกลง
  กำลังใช้งาน admin.0001_initial ... ตกลง
  กำลังใช้ admin.0002_logentry_remove_auto_add ... ตกลง
  กำลังใช้ admin.0003_logentry_add_action_flag_choices ... ตกลง
  กำลังใช้ contenttypes.0002_remove_content_type_name ... ตกลง
  กำลังใช้ auth.0002_alter_permission_name_max_length ... ตกลง
  กำลังใช้ auth.0003_alter_user_email_max_length ... ตกลง
  กำลังใช้ auth.0004_alter_user_username_opts ... ตกลง
  กำลังใช้ auth.0005_alter_user_last_login_null ... ตกลง
  กำลังใช้ auth.0006_require_contenttypes_0002 ... ตกลง
  กำลังใช้ auth.0007_alter_validators_add_error_messages ... ตกลง
  กำลังใช้ auth.0008_alter_user_username_max_length ... ตกลง
  กำลังใช้ auth.0009_alter_user_last_name_max_length ... ตกลง
  ใช้ auth.0010_alter_group_name_max_length ... ตกลง
  กำลังใช้ auth.0011_update_proxy_permissions ... ตกลง
  กำลังใช้เซสชัน.0001_initial ... ตกลง

Django ได้ใช้การย้ายข้อมูลทั้งหมดกับฐานข้อมูลเริ่มต้น:

1 ประเภทเนื้อหา 0001_initial 2019-11-13 16: 51: 04.767382
2 รับรองความถูกต้อง 0001_initial 2019-11-13 16: 51: 04.792245
3 ผู้ดูแลระบบ 0001_initial 2019-11-13 16: 51: 04.827454
4 ผู้ดูแลระบบ 0002_logentr 2019-11-13 16: 51: 04.846627
5 ผู้ดูแลระบบ 0003_logentr 2019-11-13 16: 51: 04.864458
6 ประเภทเนื้อหา 0002_remove_ 2019-11-13 16: 51: 04.892220
7 รับรองความถูกต้อง 0002_alter_p 2019-11-13 16: 51: 04.906449
8 รับรองความถูกต้อง 0003_alter_u 2019-11-13 16: 51: 04.923902
9 รับรองความถูกต้อง 0004_alter_u 2019-11-13 16: 51: 04.941707
10 รับรองความถูกต้อง 0005_alter_u 2019-11-13 16: 51: 04.958371
11 การตรวจสอบ 0006_require 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 รับรองความถูกต้อง 0011_update_ 2019-11-13 16: 51: 05.054449
17 เซสชัน 0001_initial 2019-11-13 16: 51: 05.063868

ตอนนี้เราสร้างแบบจำลองBaz:

models.py:

from django.db import models

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

ลงทะเบียนแอปbarลงในINSTALLED_APPS( foo/settings.py) และสร้าง themigrations:

python manage.py makemigrations bar

ก่อนที่เราจะทำการโยกย้ายข้อมูลที่เราสร้างขึ้นrouters.pyภายในbarแอพ:

คลาส BarRouter (วัตถุ):
    def db_for_read (ตัวเองแบบคำแนะนำ **):
        ถ้า model._meta.app_label == 'bar':
            กลับ 'ระยะไกล'
        กลับไม่มี

    def db_for_write (ตัวเองแบบคำแนะนำ **):
        ถ้า model._meta.app_label == 'bar':
            กลับ 'ระยะไกล'
        กลับไม่มี

    def allow_relation (self, obj1, obj2, ** คำแนะนำ):
        กลับไม่มี

    def allow_migrate (ตนเอง, db, app_label, model_name = ไม่มี, ** คำแนะนำ):
        หาก app_label == 'บาร์':
            return db == 'ระยะไกล'
        ถ้า db == 'remote':
            กลับเท็จ
        กลับไม่มี

และลงทะเบียนในfoo/settings.py:

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

ตอนนี้วิธีการที่ไร้เดียงสาก็คือการเรียกใช้การย้ายข้อมูลสำหรับbarลงในremoteฐานข้อมูล

python manage.py migrate bar --database=remote
การดำเนินการที่จะดำเนินการ: 
  ใช้การย้ายข้อมูลทั้งหมด:แถบ
 กำลังเรียกใช้การย้ายข้อมูล:
  กำลังใช้ bar.0001_initial ... ตกลง

การโอนย้ายถูกใช้กับremoteฐานข้อมูล:

1 บาร์ 0001_initial 2019-11-13 17: 32: 39.701784

เมื่อเราวิ่ง:

python manage.py runserver

คำเตือนต่อไปนี้จะได้รับการยก:

คุณมีการโยกย้ายที่ยังไม่ได้ใช้ 1 รายการ โครงการของคุณอาจทำงานไม่ถูกต้องจนกว่าคุณจะใช้การย้ายข้อมูลสำหรับแอพ: แถบ
เรียกใช้ 'python Manage.py โยกย้าย' เพื่อใช้

ดูเหมือนว่าทุกอย่างจะทำงานได้ดี อย่างไรก็ตามมันไม่พอใจที่มีคำเตือนนี้

วิธีที่เหมาะสมคือการเรียกใช้การย้ายข้อมูลทั้งหมดสำหรับแต่ละฐานข้อมูลตามที่แนะนำในคำตอบนี้

มันจะมีลักษณะเช่นนี้:

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

และหลังจากสร้างการโยกย้ายสำหรับbar:

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

เราเตอร์จะดูแลว่าตารางbar_bazถูกสร้างขึ้นในremoteฐานข้อมูลเท่านั้น แต่ Django จะทำเครื่องหมายการย้ายข้อมูลตามที่ใช้ในฐานข้อมูลทั้งสอง นอกจากนี้ยังมีตารางสำหรับauth, admin, sessionsฯลฯ จะถูกสร้างขึ้นเฉพาะในฐานข้อมูลตามที่ระบุไว้ในdefault routers.pyตารางdjango_migrationsในremoteฐานข้อมูลจะมีระเบียนสำหรับการย้ายข้อมูลเหล่านี้ด้วย

มันเป็นอ่านนาน แต่ผมหวังว่ามันหายไฟบางส่วนเกี่ยวกับเรื่องนี้ในความคิดของฉันไม่ได้อธิบายอย่างละเอียดปัญหาอย่างเป็นทางการในเอกสาร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.