Django使用OneToOneField跨表查询报错:api_key_id不能为空如何解决?
解决Django中Setting模型get_or_create触发的IntegrityError错误
问题场景
模型定义
class Key(models.Model): api_key=models.CharField(max_length=100,unique=True) api_key_name=models.CharField(max_length=100) def __str__(self): return self.api_key class Setting(models.Model): api_key=models.OneToOneField(Key,on_delete=models.CASCADE) field_en=models.BooleanField(default=False) def __str__(self): return str(self.api_key)
已存在数据
Key表中已添加数据:
api_key="abc1" api_key_name="test"
视图代码
def keyForm(request): key="abc1" data, created = Setting.objects.get_or_create(api_key__api_key=key) key = Key.objects.get(api_key=key) data = {'setting':data, 'key':key} return render(request,'key_form.html', data)
报错信息
MySQLdb._exceptions.OperationalError: (1048, "Column 'api_key_id' cannot be null") IntegrityError at /keyForm (1048, "Column 'api_key_id' cannot be null")
问题原因与修复
原因
get_or_create的执行逻辑是:先通过api_key__api_key=key查询Setting记录,若不存在则新建一条。但新建时未指定必填的api_key关联字段(即对应的Key实例),导致数据库要求的api_key_id字段为空,触发完整性约束错误。
修复方案
方案一(推荐,高效)
先获取对应的Key实例,再用该实例作为get_or_create的查询条件,创建时会自动关联该实例:
def keyForm(request): key_str = "abc1" # 先查询到对应的Key实例 key = Key.objects.get(api_key=key_str) # 用Key实例作为查询条件,不存在则创建关联该实例的Setting data, created = Setting.objects.get_or_create(api_key=key) context = {'setting': data, 'key': key} return render(request, 'key_form.html', context)
方案二(备选)
使用defaults参数明确指定创建Setting时的关联Key实例:
def keyForm(request): key_str = "abc1" data, created = Setting.objects.get_or_create( api_key__api_key=key_str, defaults={'api_key': Key.objects.get(api_key=key_str)} ) key = Key.objects.get(api_key=key_str) context = {'setting': data, 'key': key} return render(request, 'key_form.html', context)
说明
方案一只会查询一次Key表,性能更优;方案二在需要创建新Setting时会额外查询一次Key表,性能稍差,因此优先选择方案一。
内容的提问来源于stack exchange,提问作者user572575
相关产品推荐
相关产品推荐

