[英]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
不存在。
有人知道解決方案嗎?
我試圖使用兩個數據庫來模擬您的情況,並在下面找到解決方案:
schema1
(讀和寫) schema2
python manage.py makemigrations
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
。
顯式指定數據庫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`);
在schema1
數據庫中手動運行修訂的sql。
告訴django我自己運行了遷移: python manage.py migrate --fake
完成!
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
OneToOne
和ForeignKey
之間是有區別的:由於您專門提到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'
[...]
OneToOne
和ForeignKey
之間的區別是這樣的:
關於OneToOne
,從概念上講,這類似於具有unique = True的ForeignKey,但是關系的“反向”側將直接返回單個對象。
與OneToOneField“反向”關系相反,ForeignKey“反向”關系返回QuerySet。
由於您的應用程序管理TableA
,因此擺脫table_schema
和db_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.