【问题标题】:Updating one-to-many reference field in Django also updates other objects更新 Django 中的一对多引用字段也会更新其他对象
【发布时间】:2014-09-24 06:42:27
【问题描述】:

我有一个现有的数据库,其中包含两个表,称为身份和帐户,我正在尝试使用 Django ORM 对其进行管理。

Identities 与 Accounts 是一对多的关系,我将这两个表建模如下:

class Identity(models.Model):
    class Meta:
        managed = False
        db_table = "Identities"
    i_id = models.AutoField(db_column = "I_ID", primary_key = True) 
    name = models.CharField(db_column = "DisplayName", max_length = 200)

class Account(models.Model):
    class Meta:
        managed = False
        db_table = "Accounts"
    name = models.CharField(db_column = "Name", max_length = 200, primary_key = True)
    identity = models.ForeignKey("Identity", db_column = "I_ID", blank = True, null = True, related_name = "accounts")

我的问题是,当我更新与帐户关联的身份时,与新身份关联的所有帐户都会切换到新身份:

old_identity = Identity.objects.create(name = "Old")
new_identity = Identity.objects.create(name = "New")
account_1 = Account.objects.create(name = "account_1", identity = old_identity)
account_2 = Account.objects.create(name = "account_2", identity = old_identity)

# change the identity for account_1:
account_1.identity = new_identity
account_1.save()

# read account_2 from DB and check identity
account_2 = Account.objects.get(name = "account_2")

# identity is now "New" also for account_2!
print account_2.identity.name 

如果我直接在数据库中做同样的更新,只有我改的账号的身份发生了变化,并不是所有的账号都关联到了这个身份,所以这是Django引入的东西。

当我更改identity 字段时,我应该怎么做才能只更新一个帐户?

注意:为了清楚起见,数据库中的两个引用也都发生了变化,这不是数据未刷新或类似问题的问题。

【问题讨论】:

  • @danihp:根据您的建议更改了代码,谢谢。结果当然是一样的。
  • 这是两个模型的完整代码吗?您是否定义了任何自定义管理器或任何其他方法?
  • @DanielRoseman:模型有更多字段(电子邮件、域...),但相关位在那里。我没有自定义管理器。在类上定义了一些方法,但即使我不调用它们也会出现问题。我认为这可能与关系的定义有关......

标签: python django django-models orm


【解决方案1】:

从已发布的相关代码中检查问题。发布的代码按预期运行:

创建表格:

(venv)dani@egg-v3:~/tmp/lldldl/paolo$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: mytest
  Apply all migrations: admin, contenttypes, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
    Creating table mytest_identity
    Creating table mytest_account
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying sessions.0001_initial... OK

跑步:

(venv)dani@egg-v3:~/tmp/lldldl/paolo$ python manage.py shell
Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from mytest.models import Account,Identity
>>> old_identity = Identity.objects.create(name = "Old")
>>> new_identity = Identity.objects.create(name = "New")
>>> account_1 = Account.objects.create(name = "account_1", 
                                       identity = old_identity)
>>> account_2 = Account.objects.create(name = "account_2", 
                                       identity = old_identity)
>>> 
>>> # change the identity for account_1:
>>> account_1.identity = new_identity
>>> account_1.save()
>>> 
>>> # read account_2 from DB and check identity
>>> account_2 = Account.objects.get(name = "account_2")
>>> 
>>> # identity is now "New" also for account_2!
>>> print account_2.identity.name 
Old
>>> 

用 django 1.7 和 sqlite3 测试。也许一些数据库触发器?后/预保存信号?

【讨论】:

  • 请您打印语句之间的所有主键。
  • 当然,更改答案中的代码,我会将其复制到我的 shell 中。一切准备就绪后给我发评论。
  • @danihp:感谢您抽出宝贵时间对此进行测试 - 最后它是在导致问题的一个表上定义的双主键...
猜你喜欢
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-14
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
相关资源
最近更新 更多