You can do this in an overridden save
method. The thing to remember is that Django model instances aren't the actual database objects, they just get their values from there on load. So you can easily go back to the database before saving your current object to get the existing values.
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)
There is currently no good way of returning an error message to the user other than raising an exception. There is a Google Summer of Code project currently under way to enable 'model validation', but this will not be ready for a few months.
If you want to do something similar in the admin, the best way is to define a custom ModelForm with an overridden clean()
method. However, this time since this is a form you already have access to the old values without hitting the db again. Another benefit is that you can return a form validation error to the user.
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