Django Model OneToOneField 无需创建额外的 _id 数据库列
Posted
技术标签:
【中文标题】Django Model OneToOneField 无需创建额外的 _id 数据库列【英文标题】:Django Model OneToOneField without creating additional _id database column 【发布时间】:2014-11-29 02:31:33 【问题描述】:我正在使用 Account 模型,我想将它与 Settings 模型内部连接,而不必在我的 Account 模型中创建额外的 settings_id
列,因为 Account 表上的 PK 与设置上的 PK准确的表。我一直在尝试在这些表和列之间建立 OneToOne 关系,但不知道如何在不必创建新列或其他东西的情况下做到这一点。我正在尝试尽可能多地使用现有架构,并且不希望创建不必要的列。
Class Account(models.Model):
login_id = models.AutoField(primary_key=True)
settings = models.OneToOneField('Settings', to_field='login_id', null=True,
related_name='settings', db_column='login_id') # Doesn't work because login_id already exists....
Class Settings(model.Model):
login_id = models.OneToOneField('Account', to_field='login_id', related_name='account')
基本上,我要复制的查询是:
SELECT * FROM account
INNER JOIN settings
ON account.login_id=settings.login_id
WHERE account.login_id=1
基于错误,Django 的 ORM 似乎确实坚持在 Account 表中创建新列,但是当 2 个表之间的关系如此简单时,我看不出添加新列的意义:account.login_id = settings.login_id
【问题讨论】:
为什么两个模型相互指向是一对一的关系?您不需要在双方都指定。在其中任何一个上删除它。可通过 ORM 访问的正向和反向关系 既然他们是相关的,这似乎是合乎逻辑的。我认为这不会导致我正在创建的错误,但我会尝试从“设置”模型中删除关系,看看是否有帮助。 这将是问题的一部分。另一件事是 - 你到底想达到什么目的?在典型情况下,您似乎不必运行这样的查询。 我有每个用户的帐户表和每个用户的设置表。这些表上的 PK 是相同的。我正在处理应用程序的设置部分,我们将在功能完成后为每个用户回填设置。因此,尚未为每个用户提供设置。我想设置模型以便强制执行相同的 PK(我认为双方的 OneToOne 会这样做) 同意。这是实现此目的的一种方法(至少让您入门):***.com/questions/2846029/… - 在保存时检查对象是否存在,如果不存在,则创建并分配。 【参考方案1】:虽然我自己从未尝试过,但将 OneToOneField
声明为主键应该可以。
class Account(models.Model):
login_id = models.AutoField(primary_key=True)
class Settings(model.Model):
account = models.OneToOneField('Account', to_field='login_id',
primary_key=True, related_name='settings')
声明primary_key
将阻止Django 尝试为您创建主键列,并且通过此设置,您可以访问account.settings
和settings.account
或settings.account_id
。
【讨论】:
谢谢,这就是答案。我对related_name
的工作原理没有完全了解。使用我正在使用的架构,我不需要使用您提出的 primary_key=True
建议。
对我来说很奇怪,您可以基本上从另一个模型的属性中的参数定义一个模型的属性。看起来它会构建一个非常大的代码库,其中包含很多模型关系,让人有点难以理解。
@CoryDanielson:明确和不重复自己之间存在着内在的张力。 Django 一直更喜欢 DRY,而 SQLAlchemy 让你在关系的两端定义字段(我认为)。 Django 的方法对我来说是正确的;另一方面,在 ManyToManyField
的情况下,在幕后创建了一个全新的表,我几乎总是更喜欢明确地设置该表。
是的,我想命名约定应该足够强大,以至于您不必考虑从什么模型/表派生属性。我想我只是带着更明确的期望进入 Django。【参考方案2】:
这是我最终做的:
class Account(models.Model):
login_id = models.AutoField(primary_key=True)
def get_settings_dict(self):
try:
return self.settings.to_dict()
except Settings.DoesNotExist:
return Settings.get_defaults_dict()
class Settings(model.Model):
account = models.OneToOneField('Account', to_field='login_id', related_name='settings')
# other settings properties
# other settings properties
def to_dict(self):
# return current values as dict
@staticmethod
def get_defaults_dict():
# return default values dict
这使我可以通过account.settings
访问用户的设置,而无需在帐户模型上创建额外的settings_id
列。两个模型都不需要 OneToOne 关系。
此外,当用户的设置尚不存在时,get_settings_dict
方法会返回默认设置。这是一个很好的便利,让我不必在每次通过account.settings
访问用户设置时都进行空检查。
【讨论】:
以上是关于Django Model OneToOneField 无需创建额外的 _id 数据库列的主要内容,如果未能解决你的问题,请参考以下文章