Python 保存带有外键的django模型时,如何一次保存所有外键?

Python 保存带有外键的django模型时,如何一次保存所有外键?,python,django,Python,Django,我目前有以下型号 class Chat(models.Model): id = models.BigAutoField(primary_key=True) subject = models.CharField(max_length=200) last_message = models.OneToOneField(to='Message', on_delete=models.P

我目前有以下型号

class Chat(models.Model):
    id   = models.BigAutoField(primary_key=True)

    subject      = models.CharField(max_length=200)

    last_message = models.OneToOneField(to='Message',
                                        on_delete=models.PROTECT,
                                        related_name='last_chat')

class Message(models.Model):
    id   = models.BigAutoField(primary_key=True)

    chat = models.ForeignKey(to='Chat',
                             on_delete=models.CASCADE)

    user = models.ForeignKey(to='accounts.User',
                             on_delete=models.PROTECT)

    text = models.CharField(max_length=200)

    date = models.DateTimeField()
问题是,为了创建一个新的聊天室,我必须插入一个新的
聊天
对象和一个新的
消息
对象

但由于它们都相互引用,因此插入其中一个将导致ForeignKey约束错误


我如何解决这个问题?延迟外键的强制执行,直到我保存了这两个

之后。正如您所说,问题是您有一个循环关系。但我认为你不需要它;
last\u message
字段是不必要的,因为您总是可以通过执行
chat.message\u set.order\u by('date')来查询最后一条消息。last()
我建议使用信号来设置最后一条消息。首先,我们需要将
last_消息
设为空

class Chat(models.Model):
    id   = models.BigAutoField(primary_key=True)

    subject      = models.CharField(max_length=200)

    last_message = models.OneToOneField(to='Message', null=True,
                                        on_delete=models.PROTECT,
                                        related_name='last_chat')
class Message(models.Model):
    ...

# example of signal
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Message)
def set_last_message(sender, instance, created, **kwargs):
    if created:
        Chat.objects.filter(id=instance.chat_id).update(last_message=instance)

# in your controller code
chat = Chat.objects.create(...)
Message.objects.create(chat=chat, ...) # so your last_message will be set on this line
注(31.01.20):


这可以在较新的django版本中实现,而无需通过
Window
函数进行反规范化

尝试通过添加
blank=True,null=True
@Selcuk使
最后一条消息可为null,但我不希望它为null,注意_delete=models上的
。PROTECT
数据库中的引用完整性不允许您这样做。您应该允许它变为null,然后在保存
Chat
对象后填充它。或者,您可以在数据库中保留一个虚拟
消息
对象作为初始值。但它有点粗糙。如果将
最后一条消息设置为可空,效果会更好。如果不创建消息,您的用户就无法创建聊天室?@SardorbekImomaliev因此,基本上,我会插入所有具有空值的内容,并在它们出现在表中时进行更新。这种非规范化是必要的,因为他需要查询带有最后消息的聊天室