我想将模型的记录限制为每个用户最多 10 行(该模型具有用户模型的外键)。最佳实践是什么?
我考虑过重写保存方法,执行检查,然后在保存之前删除:
def save(self, *args, **kwargs):
if MyModel.objects.filter(user=self.user).count() >= 10:
oldest_record = MyModel.objects.filter(user=self.user).order_by('created_at').first()
oldest_record.delete()
super().save(*args, **kwargs)
但我想知道这是否是一个好的解决方案,在数据库级别强制执行是否更好(以及如何做到这一点),以及同一用户同时保存两个实例时的潜在问题(尽管可能性很小)。有类似经历吗?
您可以使用
user_id
而不是 user
来提高效率,因为它会阻止获取用户。
我们还可以一次获取所有项目,从而防止某些竞争条件:
def save(self, *args, **kwargs):
if instance._state.adding:
items = (
MyModel.objects.filter(user_id=self.user_id)
.order_by('created_at')
.only('pk')[10:]
)
if items:
MyModel.objects.filter(pk__in={item.pk for item in items}).delete()
super().save(*args, **kwargs)
但是重写
.save()
方法、信号等都可以通过批量操作(例如批量创建)来规避。
如果在数据库级别强制执行更好(以及实现方法是什么)。
您可以在数据库级别使用
UniqueConstraint
强制执行此操作,使user_id
和主键模10的组合唯一。在这种情况下,逻辑将转向选择一个好的主键。
因此,这意味着对于用户来说,我们可以为其分配例如具有主键
51
、26
、32
等的项目,但不能再次分配 31
,因为 …1
已经被“选择” .
可能最好定期运行管理命令来清理旧记录,并且在前端始终将用户的
MyModel
数量限制为十个。这可能相当稳健。