I have a status field which has 3 values: pending, activated and rejected. If I am changing the value of status I want to have a check that activated cannot be changed to pending. I do not want to write stored-procs for this. Can I have the previous value in Django before saving?
我有一个状态字段,其中包含3个值:待处理,已激活和已拒绝。如果我要更改状态值,我想要检查激活无法更改为待处理。我不想为此编写存储过程。在保存之前,我可以在Django中使用之前的值吗?
Means new and old value.
意味着新旧价值。
5 个解决方案
#1
10
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
This method is to be added in a Form
subclass. Its name is clean_FIELD_NAME
.
此方法将添加到Form子类中。它的名字是clean_FIELD_NAME。
cleaned_data
contains previous values. New value is stored in self.instance
.
cleaning_data包含以前的值。新值存储在self.instance中。
Alternatively, validate()
method can be added to a forms.Field
subclass. See Django documentation.
或者,可以将validate()方法添加到forms.Field子类中。请参阅Django文档。
#2
8
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.
您可以在重写的保存方法中执行此操作。要记住的是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)
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.
除了引发异常之外,目前没有向用户返回错误消息的好方法。目前正在进行Google Summer of Code项目以启用“模型验证”,但这将在几个月内完成。
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.
如果要在管理中执行类似操作,最好的方法是使用重写的clean()方法定义自定义ModelForm。但是,这次是因为这是一个表单,您已经可以访问旧值而无需再次访问数据库。另一个好处是您可以向用户返回表单验证错误。
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
#3
1
This has been answered elsewhere on Stack Overflow, but the correct way is to use something like this to track whether fields are dirty. Then you could use a signal to denote that something has changed that's of importance. (i.e. your field)
这已在Stack Overflow的其他地方得到解答,但正确的方法是使用类似的东西来跟踪字段是否脏。然后你可以使用一个信号来表示某些事情发生了重要变化。 (即你的领域)
#4
0
Instead of overriding the save method, wouldn't this be a good place to use signals? Intercept the save before commit, check the current value in the database, and either forward the save on, or reject it?
而不是覆盖保存方法,这不是一个使用信号的好地方吗?在提交之前拦截保存,检查数据库中的当前值,并转发保存或拒绝它?
Now I'm not sure if the signal blocks the save request or if it happens asynch, so feel free to downvote this answer if a signal can not be used to prevent the save happening upon validation.
现在我不确定信号是否阻止了保存请求,或者它是否发生异步,所以如果信号无法用于防止验证时发生保存,请随时关注此答案。
I'm against overriding inbuilt methods if there is another inbuilt tool that works just as well.
如果有另一个内置工具同样有效,我反对覆盖内置方法。
#5
0
Found this thread while searching for an answer to the same question. Why not do something like this? This way you can avoid touching database. And inbuilt __init__
just a little extended. I think it's much more simple way than using signals.
在搜索同一问题的答案时找到此主题。为什么不做这样的事情?这样就可以避免触及数据库。内置__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)
#1
10
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
This method is to be added in a Form
subclass. Its name is clean_FIELD_NAME
.
此方法将添加到Form子类中。它的名字是clean_FIELD_NAME。
cleaned_data
contains previous values. New value is stored in self.instance
.
cleaning_data包含以前的值。新值存储在self.instance中。
Alternatively, validate()
method can be added to a forms.Field
subclass. See Django documentation.
或者,可以将validate()方法添加到forms.Field子类中。请参阅Django文档。
#2
8
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.
您可以在重写的保存方法中执行此操作。要记住的是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)
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.
除了引发异常之外,目前没有向用户返回错误消息的好方法。目前正在进行Google Summer of Code项目以启用“模型验证”,但这将在几个月内完成。
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.
如果要在管理中执行类似操作,最好的方法是使用重写的clean()方法定义自定义ModelForm。但是,这次是因为这是一个表单,您已经可以访问旧值而无需再次访问数据库。另一个好处是您可以向用户返回表单验证错误。
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
#3
1
This has been answered elsewhere on Stack Overflow, but the correct way is to use something like this to track whether fields are dirty. Then you could use a signal to denote that something has changed that's of importance. (i.e. your field)
这已在Stack Overflow的其他地方得到解答,但正确的方法是使用类似的东西来跟踪字段是否脏。然后你可以使用一个信号来表示某些事情发生了重要变化。 (即你的领域)
#4
0
Instead of overriding the save method, wouldn't this be a good place to use signals? Intercept the save before commit, check the current value in the database, and either forward the save on, or reject it?
而不是覆盖保存方法,这不是一个使用信号的好地方吗?在提交之前拦截保存,检查数据库中的当前值,并转发保存或拒绝它?
Now I'm not sure if the signal blocks the save request or if it happens asynch, so feel free to downvote this answer if a signal can not be used to prevent the save happening upon validation.
现在我不确定信号是否阻止了保存请求,或者它是否发生异步,所以如果信号无法用于防止验证时发生保存,请随时关注此答案。
I'm against overriding inbuilt methods if there is another inbuilt tool that works just as well.
如果有另一个内置工具同样有效,我反对覆盖内置方法。
#5
0
Found this thread while searching for an answer to the same question. Why not do something like this? This way you can avoid touching database. And inbuilt __init__
just a little extended. I think it's much more simple way than using signals.
在搜索同一问题的答案时找到此主题。为什么不做这样的事情?这样就可以避免触及数据库。内置__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)