【问题标题】:Automatically creating a OneToOneField when accessed访问时自动创建 OneToOneField
【发布时间】:2013-03-09 00:59:25
【问题描述】:

我有两个模型:

class Profile(models.Model):
    # (...)
    settings = models.OneToOneField('Settings', null=True)
    # (...)

class Settings(model.Model):
    # (...)

有没有办法在访问 Profile#settings 时创建 Settings 的实例?

更新:我想要这个的主要动机是我已经有了 Profile 模型,并且我希望延迟创建 Setting 关系当用户点击需要 Profile#setting 实例的应用程序点时,而不关心它是否被创建。

更新: @miki725 在下面说这已经由 Django 处理了。我尝试了以下方法:

class SettingsTest(TestCase):
    def setUp(self):
        user = User.objects.create(username='felipe', email='something@aol.com')
        self.profile = Profile.objects.create(short_name='Felipe', name='Felipe',
            user=user)

    def test_settings(self):
        self.assertIsNotNone(self.profile.settings)

我明白了:

Creating test database for alias 'default'...
F
======================================================================
FAIL: test_settings (activity.tests.settings.SettingsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/vagrant/activity/tests/settings.py", line 20, in test_settings
    self.assertIsNotNone(self.profile.settings)
AssertionError: unexpectedly None

----------------------------------------------------------------------
Ran 1 test in 0.003s

【问题讨论】:

  • 您可能想解释一下您所说的访问是什么意思。可能可以通过覆盖SettingsDoesNotExists 异常或settings 对象管理器来实现。
  • @Rohan 我希望当我执行 profile.settings 时,我会得到一个新的 Settings 实例,其中包含所有默认字段以及与 Profile的关联> 实例到位。
  • 你能举个例子吗?
  • 您是否正在执行保存操作,并且您需要在保存之前为您的配置文件设置一个设置实例?

标签: python django one-to-one relation


【解决方案1】:

这是由 Django 自动完成的!

>>> p = Profile.objects.get(...)
>>> isinstance(p.settings, Settings)
True

更新

如果你得到 None,这意味着 Profile 模型中的外键值为空,因为你允许空值 null=True。在这种情况下,你真的什么都做不了:

>>> p = Profile(settings=None, ...)
>>> p.save()
>>> p = Profile.objects.get(pk=p.pk)
>>> p.settings # the settings can't be anything because you never assigned them
None

如果您需要这个进行测试,那么您必须为 Profile 实例分配一些设置值:

class SettingsTest(TestCase):
    def setUp(self):
        user = User.objects.create(username='felipe', email='something@aol.com')
        self.settings = Settings.objects.create(...)
        self.profile = Profile.objects.create(short_name='Felipe',
                                              name='Felipe',
                                              user=user,
                                              settings=self.settings)

顺便说一句,从 Django 1.5 开始,您可以配置您的用户模型。在您必须创建一个必须与用户模型具有一对一键的配置文件模型之前。现在不再需要了。您可以将字段添加到用户模型。您可以在 Django 1.5 版本文档 (https://docs.djangoproject.com/en/dev/releases/1.5/#configurable-user-model) 中了解更多相关信息。

更新

现在您的动机更加明确,您可以使用这种骇人听闻的方法来实现。我认为这不是最好的方法,但应该可以:

Profile(models.Model):
    def get_default_settings(self):
        settings = Settings.objects.create(...)
        self.settings_id = settings.pk
        return settings

    def __getattribute__(self, name):
        default = object.__getattribute__(self, name)
        if name == 'settings':
            if default is None:
                return self.get_default_settings()
            else:
                return default
        else:
            return default

【讨论】:

  • 无论出于何种原因,在创建新的 Profile 时它都是 None。查看我的问题的更新。
  • 最初我没有注意到null=True 部分。我更新了我的答案。
  • 你说:“这些设置不可能是任何东西,因为你从未分配过它们”,但这正是我的问题的重点:我可以在第一次这样做的时候做到吗访问p.settings,会自动创建一个具有所有字段默认值的新设置实例?
  • 我需要的不是测试。我有一个包含大量记录的 Profile 模型,我想在第一次访问时懒惰地创建 Settings 关联,而不必主动创建它。
  • 参考更新后的答案。以后请尝试在问题中立即解释您的动机,以避免来回。
猜你喜欢
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 2016-06-04
  • 2016-01-17
  • 2023-03-13
  • 2020-10-10
  • 1970-01-01
相关资源
最近更新 更多