Django - 保存前替换模型字段值

Django - Replace model fields values before save

请注意:我知道重写模型的 方法,但它不适合我,正如我在问题末尾解释的那样。

在我的一个项目中,我有超过 30 个数据库模型,每个模型都接受多个 CharField 来存储波斯字符;但是,在某些情况下,用户可能会在键盘上使用阿拉伯语布局,其中某些字符与波斯语不同。

例如:

The name Ali in Arabic: علي
and in Persian: علی

甚至在数量上:

345 in Arabic: ٣٤٥
And in Persian: ۳۴۵

我需要有选择地选择一组这些字段,然后 运行 在保存它们之前(在创建或更新时)根据它们的值创建一个函数来映射这些字符,这样我就不会得到两个不同的结果我数据库中单个单词的形式。

一种方法是覆盖数据库模型上的 .save() 方法。有没有其他方法可以做到这一点,这样我就不必更改所有模型?

听起来 Django 的信号很好用。使用信号,您可以在保存一个或多个模型之前或之后调用函数。

https://docs.djangoproject.com/en/3.2/topics/signals/

Django includes a “signal dispatcher” which helps decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events.

django.db.models.signals.pre_save & django.db.models.signals.post_save

Sent before or after a model’s save() method is called.

https://docs.djangoproject.com/en/3.2/ref/signals/#pre-save

pre_save

django.db.models.signals.pre_save This is sent at the beginning of a model’s save() method.

Arguments sent with this signal:

sender The model class.

instance The actual instance being saved.

raw A boolean; True if the model is saved exactly as presented (i.e. when loading a fixture). One should not query/modify other records in the database as the database might not be in a consistent state yet. using The database alias being used.

update_fields The set of fields to update as passed to Model.save(), or None if update_fields wasn’t passed to save().

您可以将信号连接到应用程序中的单个、多个或所有模型。

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel

@receiver(pre_save)
def my_handler(sender, instance, **kwargs):
    # logic here

在这种情况下,发送者是即将被保存的模型,实例将是被保存的对象。

您可以创建一个完整的 custom model field 但是在您的情况下,仅自定义 Django 的 CharField:

确实更容易
class MyCharField(models.CharField):
    def to_python(self, value):
        if value is None or value == "":
            return value  # Prevent None values being converted to "None"
        if isinstance(value, str):
            return self.func_to_call(value)
        return self.func_to_call(str(value))

将您的模型 CharField 替换为 MyCharField

并创建 .func_to_call() 以便它执行映射值所需的任何操作:

def func_to_call(self, value):
    # Do whatever you want to map the values
    return value