Djangoモデルがあり、保存前にフィールドの古い値と新しい値を比較する必要があります。
Save()の継承とpre_saveシグナルを試しました。正しくトリガーされましたが、実際に変更されたフィールドのリストが見つからず、古い値と新しい値を比較できません。やり方がある?事前保存アクションの最適化に必要です。
ありがとうございました!
非常に簡単なDjangoの方法があります。
次のようにモデルinitの値を「記憶」します。
def __init__(self, *args, **kwargs):
super(MyClass, self).__init__(*args, **kwargs)
self.initial_parametername = self.parametername
---
self.initial_parameternameX = self.parameternameX
実際の例:
クラスで:
def __init__(self, *args, **kwargs):
super(MyClass, self).__init__(*args, **kwargs)
self.__important_fields = ['target_type', 'target_id', 'target_object', 'number', 'chain', 'expiration_date']
for field in self.__important_fields:
setattr(self, '__original_%s' % field, getattr(self, field))
def has_changed(self):
for field in self.__important_fields:
orig = '__original_%s' % field
if getattr(self, orig) != getattr(self, field):
return True
return False
そして、modelform saveメソッドで:
def save(self, force_insert=False, force_update=False, commit=True):
# Prep the data
obj = super(MyClassForm, self).save(commit=False)
if obj.has_changed():
# If we're down with commitment, save this shit
if commit:
obj.save(force_insert=True)
return obj
ModelFormレベルでこれを行うことをお勧めします。
そこで、saveメソッドでの比較に必要なすべてのデータを取得します。
モデルレベルでこれを行う場合は、Odifの回答で指定されている方法に従うことができます。
また、 FieldTracker from Django-model-utils を使用することもできます:
モデルにトラッカーフィールドを追加するだけです。
tracker = FieldTracker()
Pre_saveおよびpost_saveで次を使用できます。
instance.tracker.previous('modelfield') # get the previous value
instance.tracker.has_changed('modelfield') # just check if it is changed
ModelFormでこれを行う方がより簡単で簡単だというSahilの意見に同意します。ただし、ModelFormのcleanメソッドをカスタマイズし、そこで検証を実行します。私の場合、モデルのフィールドが設定されている場合、モデルのインスタンスが更新されないようにしました。
私のコードは次のように見えました。
from Django.forms import ModelForm
class ExampleForm(ModelForm):
def clean(self):
cleaned_data = super(ExampleForm, self).clean()
if self.instance.field:
raise Exception
return cleaned_data
モデルを保存する直前に、フィールドの以前および現在の値にアクセスできるアプリを次に示します。 Django-smartfields
Nice宣言型mayでこの問題を解決する方法は次のとおりです。
from Django.db import models
from smartfields import fields, processors
from smartfields.dependencies import Dependency
class ConditionalProcessor(processors.BaseProcessor):
def process(self, value, stashed_value=None, **kwargs):
if value != stashed_value:
# do any necessary modifications to new value
value = ...
return value
class MyModel(models.Model):
my_field = fields.CharField(max_length=10, dependencies=[
Dependency(processor=ConditionalProcessor())
])
さらに、このプロセッサは、フィールドの値が置き換えられた場合にのみ呼び出されます
これの私の使用例は、フィールドが値を変更するたびにモデルに非正規化値を設定する必要があったことです。ただし、監視対象のフィールドはm2mリレーションであるため、非正規化フィールドの更新が必要かどうかを確認するためにsaveが呼び出されるたびにそのDBルックアップを行う必要はありませんでした。そこで、必要に応じて非正規化フィールドのみを更新するために、代わりにこの小さなmixinを作成しました(@Odif Yitsaebの回答をインスピレーションとして使用)。
class HasChangedMixin(object):
""" this mixin gives subclasses the ability to set fields for which they want to monitor if the field value changes """
monitor_fields = []
def __init__(self, *args, **kwargs):
super(HasChangedMixin, self).__init__(*args, **kwargs)
self.field_trackers = {}
def __setattr__(self, key, value):
super(HasChangedMixin, self).__setattr__(key, value)
if key in self.monitor_fields and key not in self.field_trackers:
self.field_trackers[key] = value
def changed_fields(self):
"""
:return: `list` of `str` the names of all monitor_fields which have changed
"""
changed_fields = []
for field, initial_field_val in self.field_trackers.items():
if getattr(self, field) != initial_field_val:
changed_fields.append(field)
return changed_fields
このようなものも動作します:
class MyModel(models.Model):
my_field = fields.IntegerField()
def save(self, *args, **kwargs):
# Compare old vs new
if self.pk:
obj = MyModel.objects.values('my_value').get(pk=self.pk)
if obj['my_value'] != self.my_value:
# Do stuff...
pass
super().save(*args, **kwargs)