Django OneToOneField 通过在 save() 之后返回 None 来失去关系
Posted
技术标签:
【中文标题】Django OneToOneField 通过在 save() 之后返回 None 来失去关系【英文标题】:Django OneToOneField looses relation by returning None after save() 【发布时间】:2021-12-13 11:09:44 【问题描述】:我对 Django 的行为有点困惑,我在任何相关问题或官方文档中都找不到。
例如,在下面的代码中:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255)
class Post(models.Model):
title = models.CharField(max_length=255)
category = models.OneToOneField(Category)
post = Post(title='My Title')
post.category = Category(name='My Category')
post.category.save()
# Here: post.category => Category(pk=1, name="My Category") ????
# Great the category has been saved and has a primary key, and is on the `post` instance (that still needs to be saved)
post.save()
# Here: post.category => None ????
# Why did the saving of post loose the category that was created and linked to the post ?
我创建了一个 Post 对象。然后,我在其上创建一个类别,然后在保存帖子之前保存该类别。但是当我调用post.save()
方法时,post.category
被清除并设置为无。这是为什么呢?
我已通过以下方法修复它,其中引入了一个额外的 category
变量:
post = Post(title='My Title')
category = Category(name='My Category')
category.save()
post.category = category
# Here: post.category => Category(pk=1, name="My Category") ????
post.save()
# Here: post.category => Category(pk=1, name="My Category") ????
为什么引入一个额外的变量会改变save()
方法的行为?在调用post.save()
之前检查post.category
时,post.category
的值在两种情况下都是相同的。
【问题讨论】:
【参考方案1】:由于 django 使用 lazy 作为查询集,数据库事务在调用 save() 之前不会执行:
post = Post(title='My Title')
# cool you created a post instance of Post model(not database record)
post.category = Category(name='My Category')
# you set the instance attribute value to an instance of Category model
post.category.save()
# calling save() execute database transaction -> it create category object in DB -> your post instance with its attribute never get saved
post.save()
# now you only be saving Post(title='My Title')
我不认为这是最好的答案,但它解释了流程
TLDR:您的第一个 save() 仅在 Category 实例上执行,而不是 Post 实例
来自评论讨论:
在文档 docs.djangoproject.com/en/dev/topics/db/queries/... 中提到了这一点 This example updates the blog attribute of an Entry instance entry, assuming appropriate instances of Entry and Blog are already saved to the database (so we can retrieve them below)
所以是的,当您设置某些内容时,您应该使用从数据库中检索的值。没有太多解释为什么我们应该这样做,除非你想深入研究 django 模型代码并查看它如何处理保存对象
【讨论】:
我知道第一个post.category.save()
只保存类别,这是意料之中的?
@achedeuzot 您实际上从未将 post.category
设置为类别对象,您仅将其设置为实例(数据库中尚不存在)
因此,为了将关系正确持久化到数据库,在设置category
字段时,Category
对象绝对 需要是具有数据库主数据库的实例关键?
奇怪的是,在调用post.save()
之前检查post.category
值时,post.category
实例确实设置了主键,因为它已经被保存了。跨度>
在文档docs.djangoproject.com/en/dev/topics/db/queries/… 中提到了这个This example updates the blog attribute of an Entry instance entry, assuming appropriate instances of Entry and Blog are already saved to the database (so we can retrieve them below):
所以是的,当你设置一些东西时,你应该使用从数据库中检索的值。没有太多解释为什么我们应该这样做,除非您想深入研究 django 模型代码并查看它如何处理保存对象以上是关于Django OneToOneField 通过在 save() 之后返回 None 来失去关系的主要内容,如果未能解决你的问题,请参考以下文章
Django:扩展用户时,最好使用 OneToOneField(User) 或 ForeignKey(User, unique=True)?
Django 查询 - 将用户类与 Telegram Bot 的 OnetoOnefield 类连接起来