How to check value transition in Django (django-ad

2019-04-06 19:34发布

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?

Means new and old value.

5条回答
姐就是有狂的资本
2楼-- · 2019-04-06 20:09

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.

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)
查看更多
Fickle 薄情
3楼-- · 2019-04-06 20:16

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)

查看更多
够拽才男人
4楼-- · 2019-04-06 20:17
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.

cleaned_data contains previous values. New value is stored in self.instance.

Alternatively, validate() method can be added to a forms.Field subclass. See Django documentation.

查看更多
我只想做你的唯一
5楼-- · 2019-04-06 20:17

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.

查看更多
神经病院院长
6楼-- · 2019-04-06 20:18

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
查看更多
登录 后发表回答