簡體   English   中英

另一個模式中的Django外鍵

[英]Django Foreign key in another schema

我有一個帶有2個shemas(A和B)的MySQL數據庫。
我的django應用程序可以讀寫A。
它只能從B讀取。

我的應用程序管理A中的所有表。
B已經在表(b)中包含一些數據。

我想在A和B之間添加一個一對一的字段。
像這樣的東西:

class SchemaBTableB(models.Model):
    class Meta:
        managed = False
        db_schema = 'B'
        db_table = 'b'

    [...]

class SchemaATableA(models.Model):
    class Meta:
        db_schema = 'A'
        db_table = 'a'

    id = models.OneToOneField(
        SchemaBTableB,
        on_delete=models.DO_NOTHING,
        primary_key=True
    )

    [...]

不幸的是, db_schema不存在。
有人知道解決方案嗎?

我試圖使用兩個數據庫來模擬您的情況,並在下面找到解決方案:

1.場景:

  1. 由django管理的數據庫schema1 (讀和寫)
  2. 不是由django管理的數據庫schema2

2.步驟:

  1. 為模型創建遷移python manage.py makemigrations
  2. 為您的遷移生成SQL: python manage.py sqlmigrate app 0001 假設從步驟1生成的遷移文件名為0001_initial.py

此遷移的sql應如下所示:

CREATE TABLE `user_info` (`id_id` integer NOT NULL PRIMARY KEY, `name` varchar(20) NOT NULL);
ALTER TABLE `user_info` ADD CONSTRAINT `user_info_id_id_e8dc4652_fk_schema2.user_extra_info_id` FOREIGN KEY (`id_id`) REFERENCES `user_extra_info` (`id`);
COMMIT;

如果直接運行上述sql,則會出現如下錯誤:

django.db.utils.OperationalError: (1824, "Failed to open the referenced table 'user_extra_info'")

這是因為django假定所有遷移步驟都在同一數據庫中執行 因此,它無法在schema1數據庫中找到user_extra_info

3.以下步驟:

  1. 顯式指定數據庫schema2為表user_extra_info

     ALTER TABLE `user_info` ADD CONSTRAINT `user_info_id_id_e8dc4652_fk_schema2.user_extra_info_id` FOREIGN KEY (`id_id`) REFERENCES schema2.user_extra_info (`id`); 
  2. schema1數據庫中手動運行修訂的sql。

  3. 告訴django我自己運行了遷移: python manage.py migrate --fake

  4. 完成!


源代碼供您參考:

models.py

from django.db import models


class UserExtraInfo(models.Model):
    # table in schema2, not managed by django
    name = models.CharField('name', max_length=20)

    class Meta:
        managed = False
        db_table = 'user_extra_info'


class UserInfo(models.Model):
    # table in schema1, managed by django
    id = models.OneToOneField(
        UserExtraInfo,
        on_delete=models.CASCADE,
        primary_key=True
    )
    name = models.CharField('user name', max_length=20)

    class Meta:
        db_table = 'user_info'

settings.py

# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'schema1',
        'USER': 'USER',
        'PASSWORD': 'PASSWORD',
        'HOST': 'localhost',
        'PORT': 3306,
    },
    'extra': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'schema2',
        'USER': 'USER',
        'PASSWORD': 'PASSWORD',
        'HOST': 'localhost',
        'PORT': 3306,
    }
}

DATABASE_ROUTERS = ['two_schemas.router.DBRouter']

router.py

class DBRouter(object):
    """
    A router to control all database operations on models in the
    auth application.
    """
    def db_for_read(self, model, **hints):
        """
        Attempts to read auth models go to auth_db.
        """
        if model._meta.db_table == 'user_extra_info':
            # specify the db for `user_extra_info` table
            return 'extra'
        if model._meta.app_label == 'app':
            return 'default'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth models go to auth_db.
        """
        if model._meta.db_table == 'user_extra_info':
            # specify the db for `user_extra_info` table
            return 'extra'
        if model._meta.app_label == 'app':
            return 'default'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Relations between objects are allowed if both objects are
        in the primary/replica pool.
        """
        db_list = ('default', 'extra')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth app only appears in the 'auth_db'
        database.
        """
        if app_label == 'app':
            return db == 'default'
        return None

OneToOneForeignKey之間是有區別的:由於您專門提到FK-我假設您實際上想制作一個外鍵,這是這樣完成的: ForeignKey(SomeModel, unique=True)

class ObjectTableA(models.Model):

    id = models.ForeignKey(
        ObjectTableB,
        on_delete=models.DO_NOTHING,
        unique=True,
    )

    [...]


class ObjectTableB(models.Model):
    class Meta:
        managed = False
        db_table = 'b'

    [...]

OneToOneForeignKey之間的區別是這樣的:

關於OneToOne ,從概念上講,這類似於具有unique = True的ForeignKey,但是關系的“反向”側將直接返回單個對象。

與OneToOneField“反向”關系相反,ForeignKey“反向”關系返回QuerySet。

由於您的應用程序管理TableA ,因此擺脫table_schemadb_table

在您的TableB模型中,您可能希望擺脫table_schema

編輯:由於您確定要使用OneToOne ,因此應該可以執行以下操作:

id = models.OneToOneField(
ObjectB, 
on_delete=models.DO_NOTHING,
)

由於您的ObjectA由Django管理,因此只需將OneToOne鏈接到您的ObjectB

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM