我有一个带有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
不存在。
有人知道解决方案吗?
答案 0 :(得分:1)
我曾尝试使用两个数据库来模拟您的情况,并找出以下解决方案:
schema1
,由django(读写)管理schema2
,它不是由Django管理的 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假定所有迁移步骤都在同一数据库中执行。因此无法在user_extra_info
数据库中找到schema1
。
为表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
答案 1 :(得分:0)
OneToOne
和ForeignKey
之间是有区别的:由于您是专门提到FK的-我假设您实际上想制作一个外键,方法是这样的:{{1 }}
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
,从概念上讲,这与具有unique = True的ForeignKey相似,但是关系的“反向”侧将直接返回单个对象。
与OneToOneField“反向”关系相反,ForeignKey“反向”关系返回QuerySet。
由于您的应用管理着OneToOne
,因此请摆脱TableA
和table_schema
。
在您的db_table
模型中,您可能希望摆脱TableB
编辑:由于您确定要使用table_schema
,因此应该可以执行以下操作:
OneToOne
由于您的id = models.OneToOneField(
ObjectB,
on_delete=models.DO_NOTHING,
)
由Django管理,因此只需将其ObjectA
链接到您的OneToOne
。