Django ForeignKey与数据库FOREIGN KEY约束的区别及实战
本文详解Django中ForeignKey与数据库物理外键的区别,探讨在高并发场景下通过db_constraint=False禁用物理约束以规避锁问题。同时解析如何通过ORM实现高效关联查询,并补充auto_now字段在update与save方法中的行为差异,帮助开发者优化数据库设计与运维成本。
高并发场景下禁用数据库外键约束
在高并发业务场景中,数据库若启用外键约束易引发锁竞争问题,且会显著增加运维复杂度。因此,许多企业规范明确禁止在生产环境数据库中使用外键约束。
在禁用物理外键约束的前提下,如何利用Django ORM实现表间关联查询?这曾是常见痛点,本文旨在提供解决方案并分享实践经验。
Django ForeignKey与物理外键的区别
需明确区分Django模型中的ForeignKey与数据库层面的FOREIGN KEY约束。Django的ForeignKey本质是逻辑关联,允许开发者灵活控制是否生成数据库物理外键。
针对前述高并发场景,可参考以下省与市关联的Model定义方式:
Model定义与SQL生成示例
# demo/models.py
from django.db import models
class Province(models.Model):
name = models.CharField(max_length=16)
def __unicode__(self):
return self.name
class City(models.Model):
name = models.CharField(max_length=16)
province = models.ForeignKey(Province, null=True, on_delete=models.SET_NULL,
related_name='cities', db_constraint=False)
def __unicode__(self):
return self.name
上述models.py代码在执行migrate时,针对MySQL数据库生成的SQL语句如下:
CREATE TABLE `demo_city` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(16) NOT NULL);
CREATE TABLE `demo_province` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(16) NOT NULL);
ALTER TABLE `demo_city` ADD COLUMN `province_id` integer NULL;
CREATE INDEX `demo_city_province_id_50fffd49` ON `demo_city` (`province_id`);
若未指定db_constraint=False参数,Django将在数据库中创建外键约束,生成的SQL如下:
ALTER TABLE `demo_city` ADD CONSTRAINT `demo_city_province_id_aff53934_fk_key_province_id` FOREIGN KEY (`province_id`) REFERENCES `demo_province` (`id`);
级联删除与反向关联查询
此外,ForeignKey的on_delete参数默认为on_delete=models.CASCADE,即执行数据库级联删除。若需删除Province时保留City记录并将province_id置空,应使用on_delete=models.SET_NULL。
采用上述逻辑关联方式,不会破坏Django的反向关联查询功能,以下查询仍能返回正确结果:
Province.objects.filter(cities__name='xxx')
该查询实际执行的SQL为Inner Join操作:
SELECT `demo_province`.`id`, `demo_province`.`name` FROM `demo_province` INNER JOIN `demo_city` ON (`demo_province`.`id` = `demo_city`.`province_id`) WHERE `demo_city`.`name` = xxx;
auto_now字段在update与save中的行为差异
补充说明:关于Django模型中定义auto_now=True时,数据库时间字段并未如预期自动更新的问题。
Django ORM更新数据库主要涉及update和save两种方法。
当模型中设置了auto_now=True时间戳属性以期望数据库自动更新时间时,
使用update方法更新的记录,数据库中时间字段并未自动更新,无法满足需求。
auto_now=True生效的前提是通过Django的Model层操作。
例如使用create或save方法。
若先filter再调用update方法,则直接执行SQL语句,不经过Model层逻辑,
因此不会触发时间字段的自动更新。故需使用save方法更新才能满足需求。
以上关于Django ForeignKey与数据库FOREIGN KEY约束的详解及auto_now行为分析,供读者参考。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









