Django:仅当特定字段变更时更新DateTimeField属性的实现方法
解决思路与实现代码
没问题,这是Django模型开发里很常见的需求,咱们可以通过重写模型的save()方法来精准控制date_assigned的更新时机,具体实现步骤如下:
第一步:修改字段定义
首先要移除date_assigned的auto_now=True参数——因为这个参数会让Django在每次保存对象时自动覆盖该字段值,完全剥夺我们手动控制的权限。修改后的字段定义如下:
date_assigned = models.DateTimeField(null=False)
第二步:重写save()方法
在Ip模型里添加自定义的save()方法,核心逻辑是:
- 当创建新的
Ip对象时,直接给date_assigned设置当前时间(毕竟第一次分配给客户,肯定要记录这个时间) - 当更新已存在的
Ip对象时,对比数据库中原始的customer值和当前修改后的customer值,只有两者不同时,才更新date_assigned
完整的模型代码如下:
from django.db import models from django.utils import timezone class Ip(models.Model): customer = models.ForeignKey(Customer, null=False, on_delete=models.CASCADE) ip = models.GenericIPAddressField(protocol="IPv4", null=False, unique=True) date_created = models.DateTimeField(auto_now_add=True,) date_updated = models.DateTimeField(auto_now=True,) date_assigned = models.DateTimeField(null=False) # 移除auto_now=True def save(self, *args, **kwargs): # 处理新建对象的情况 if not self.pk: self.date_assigned = timezone.now() else: # 获取数据库中保存的原始对象,对比customer是否变更 original_ip = Ip.objects.get(pk=self.pk) if original_ip.customer != self.customer: self.date_assigned = timezone.now() # 调用父类的save方法完成最终保存 super().save(*args, **kwargs)
补充说明
- 如果你担心每次更新时额外查询数据库的性能开销,可以考虑用
django.db.models.signals.pre_save信号来实现,不过对于这种简单场景,重写save()方法更直观易懂。 - 注意:如果通过
Ip.objects.filter(...).update(customer=...)这种批量更新方式修改客户,模型的save()方法不会被调用,date_assigned也不会自动更新。如果有批量更新的需求,需要在批量操作时手动设置date_assigned字段。
内容的提问来源于stack exchange,提问作者Jorge
相关产品推荐
相关产品推荐

