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
请注意:我知道重写模型的
在我的一个项目中,我有超过 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