Django自关联OneToOneField创建对象时自动绑定当前实例问题
Django 自关联OneToOneField自动绑定自身解决方案
1 修正模型字段定义
你原有代码中book_link字段设置默认值为空字符串不符合外键字段的类型要求,外键需要关联对应实例的主键值,首先调整字段定义,同时重写save方法实现自动赋值:
class Book(core.BaseModel): # 移除错误的空字符串默认值,新增null=True、blank=True允许新增时暂时留空 book_link = models.OneToOneField('self', null=True, blank=True, on_delete=models.CASCADE) book_name = models.CharField('Name', max_length=250) def save(self, *args, **kwargs): # 判断为新增实例(还未生成主键) if not self.pk: # 先调用父类save方法持久化实例,获取自增主键 super().save(*args, **kwargs) # 把自身赋值给book_link字段 self.book_link = self # 保存最终数据 super().save(*args, **kwargs)
2 可选实现:使用post_save信号
如果你不想重写模型的save方法,也可以通过Django信号机制实现相同效果:
2.1 定义信号
在你的应用目录下新建signals.py,添加如下代码:
from django.db.models.signals import post_save from django.dispatch import receiver from .models import Book @receiver(post_save, sender=Book) def bind_book_link_to_self(sender, instance, created, **kwargs): # 仅在实例首次创建时触发赋值 if created: instance.book_link = instance # 仅更新book_link字段,减少性能消耗 instance.save(update_fields=["book_link"])
2.2 注册信号
修改应用的apps.py,在ready方法中导入信号完成注册:
from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "替换为你的应用名称" def ready(self): import 替换为你的应用名称.signals
3 Admin端隐藏字段(可选)
如果你在Django管理后台中创建Book实例,不需要显示book_link的选择下拉框,可以在admin.py中配置隐藏该字段:
from django.contrib import admin from .models import Book @admin.register(Book) class BookAdmin(admin.ModelAdmin): exclude = ("book_link",)
注意事项
- 修改字段定义后需要重新生成并执行迁移,命令为
python manage.py makemigrations、python manage.py migrate - OneToOneField自关联默认要求值唯一,符合绑定自身的需求,不会出现重复绑定冲突
内容的提问来源于stack exchange,提问作者Ken Ist
相关产品推荐
相关产品推荐

