如何在保存过程中排除 django 模型字段?

2023-12-26

我有一个相当复杂的 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 表达式 https://docs.djangoproject.com/en/1.8/ref/models/expressions/#django.db.models.F在增加计数器时避免竞争条件。我通常不想将计数器的值保存在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 管理站点进行交互;代码中的所有其他位置都可以相对地轻松打电话model_obj.save()与正确的update_fields.


我最终使用了以下内容:

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=200)
    counter = models.IntegerField(default=0)

    default_save_fields = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.default_save_fields is None:
            # This block should only get called for the first object loaded
            default_save_fields = {
                f.name for f in self._meta.get_fields()
                if f.concrete and not f.many_to_many and not f.auto_created
            }
            default_save_fields.difference_update({
                'counter',
            })
            self.__class__.default_save_fields = tuple(default_save_fields)

    def increment_counter(self):
        self.counter = models.F('counter') + 1
        self.save(update_fields=['counter'])    

    def save(self, **kwargs):
        if self.id is not None and 'update_fields' not in kwargs:
            # If self.id is None (meaning the object has yet to be saved)
            # then do a normal update with all fields.
            # Otherwise, make sure `update_fields` is in kwargs.
            kwargs['update_fields'] = self.default_save_fields
        super().save(**kwargs)

这似乎适用于我的更复杂的模型,该模型在其他模型中被引用为外键,尽管可能存在一些它未涵盖的边缘情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在保存过程中排除 django 模型字段? 的相关文章

随机推荐