【发布时间】:2015-10-19 22:27:38
【问题描述】:
我有一个相当复杂的 Django 模型,其中包含一些只能在特定情况下保存的字段。举个简单的例子,
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=200)
counter = models.IntegerField(default=0)
def increment_counter(self):
self.counter = models.F('counter') + 1
self.save(update_fields=['counter'])
这里我使用F expressions 来避免在递增计数器时出现竞争条件。我通常不会希望将 counter 的值保存在 increment_counter 函数之外,因为这可能会撤消从另一个线程或进程调用的增量。
所以问题是,在模型的保存功能中默认排除某些字段的最佳方法是什么?我已经尝试了以下
def save(self, **kwargs):
if update_fields not in kwargs:
update_fields = set(self._meta.get_all_field_names())
update_fields.difference_update({
'counter',
})
kwargs['update_fields'] = tuple(update_fields)
super().save(**kwargs)
但这会导致ValueError: The following fields do not exist in this model or are m2m fields: id。我当然可以在差异更新中添加 id 和任何 m2m 字段,但这开始看起来像一个无法维护的混乱,特别是一旦其他模型开始引用这个,这将在 self._meta.get_all_field_names() 中添加其他需要的名称从update_fields 中排除。
对于它的价值,我主要需要这个功能来与 django 管理站点交互;代码中的所有其他位置都相对可以轻松地使用正确的update_fields 调用model_obj.save()。
【问题讨论】:
-
为什么将
id添加到difference_update会一团糟?对于 m2m 字段,您始终可以遍历所有get_fields()并排除它们。 -
@Ivan 当然,这适用于简单的情况,但是一旦我开始在其他模型中将此模型引用为
ForeignKey,那么我需要将所有这些字段名称添加到difference_update也是。这很快就违反了 DRY。 -
我的意思是一般地遍历所有字段,看看它们是否是反向关系。据我所知,我已经这样做了,我会检查一下。
-
您可以使用
hasattr(field,'column')。如果字段是反向关系,它将是False。我自己实际上使用了auto_created属性,但目标有点不同。 -
看起来使用
_meta.get_concrete_fields_with_model()而不是_meta.get_all_field_names()可能是要走的路,尽管它在 Django 1.8 中已被弃用。他们有一个migration guide,不过可以帮助替换它。
标签: django django-models