保留中、アクティブ化、拒否の3つの値を持つステータスフィールドがあります。ステータスの値を変更する場合、アクティブ化を保留に変更できないことを確認したいと思います。このためにストアドプロシージャを記述したくありません。保存する前にDjangoで以前の値を取得できますか?
新旧の価値を意味します。
保留中、アクティブ化、拒否の3つの値を持つステータスフィールドがあります。ステータスの値を変更する場合、アクティブ化を保留に変更できないことを確認したいと思います。このためにストアドプロシージャを記述したくありません。保存する前にDjangoで以前の値を取得できますか?
新旧の価値を意味します。
def clean_status(self):
status = self.cleaned_data.get('status')
if status == 'pending':
if self.instance and self.instance.status == 'activated':
raise forms.ValidationError('You cannot change activated to pending')
return status
このメソッドはForm
サブクラスに追加されます。その名はclean_FIELD_NAME
。
cleaned_data
以前の値が含まれています。に新しい値が格納されself.instance
ます。
または、メソッドをサブクラスvalidate()
に追加することもできます。Django のドキュメントを参照してください。forms.Field
これは、オーバーライドされたsave
メソッドで行うことができます。覚えておくべきことは、Django モデル インスタンスは実際のデータベース オブジェクトではなく、ロード時にそこから値を取得するだけだということです。したがって、現在のオブジェクトを保存して既存の値を取得する前に、データベースに簡単に戻ることができます。
def save(self, *args, **kwargs):
if self.status == 'pending':
old_instance = MyClass.objects.get(pk=self.pk)
if old_instance.status == 'activated':
raise SomeError
super(MyModel, self).save(*args, **kwargs)
現在、例外を発生させる以外に、ユーザーにエラー メッセージを返す良い方法はありません。「モデルの検証」を有効にするために現在進行中の Google Summer of Code プロジェクトがありますが、これは数か月間は準備ができていません。
管理者で同様のことをしたい場合、オーバーライドされたメソッドでカスタム ModelForm を定義するのが最善のclean()
方法です。ただし、今回はこれがフォームであるため、再度データベースにアクセスすることなく、古い値にアクセスできます。もう 1 つの利点は、フォーム検証エラーをユーザーに返すことができることです。
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def clean_status(self):
status = self.cleaned_data.get('status', '')
if status == 'pending':
if self.instance and self.instance.status == 'activated':
raise forms.ValidationError(
'You cannot change activated to pending'
)
return status
class MyModelAdmin(forms.ModelAdmin):
form = MyModelForm
model = MyModel
これは Stack Overflow の他の場所で回答されていますが、正しい方法は、このようなものを使用してフィールドがダーティかどうかを追跡することです。次に、シグナルを使用して、重要な何かが変更されたことを示すことができます。(つまり、あなたの分野)
同じ質問への回答を探しているときに、このスレッドを見つけました。なぜこのようなことをしないのですか?このようにして、データベースに触れないようにすることができます。__init__
そして少しだけ拡張された作り付け。シグナルを使用するよりもはるかに簡単な方法だと思います。
class MyModel(models.Model):
my_fair_field = ....
def __init__(self, *args, **kwargs):
super(MyModel, self).__init__(*args, **kwargs)
self.__clean_fair_field = self.my_fair_field
def save(self, *args, **kwargs):
# check if field value changed
if self.__clean_fair_field != self.my_fair_field
# ...do some work...
super(MyModel, self).save(*args, **kwargs)
save メソッドをオーバーライドする代わりに、これはシグナルを使用するのに適した場所ではないでしょうか? コミット前に保存を傍受し、データベースの現在の値を確認して、保存を転送するか拒否しますか?
シグナルが保存リクエストをブロックするのか、それとも非同期に発生するのかはわかりません。検証時に保存が発生するのを防ぐためにシグナルを使用できない場合は、この回答に反対票を投じてください。
同様に機能する別の組み込みツールがある場合、組み込みメソッドをオーバーライドすることには反対です。