Django模型:仅保存前日期和当前日期之间的最小值

时间:2016-02-19 13:17:34

标签: django

我有以下型号:

class Placement(models.Model):
    name = models.CharField(max_length=500, blank=False)
    actual_start_date = models.DateField(blank=True, null=True)
    actual_end_date = models.DateField(blank=True, null=True)
    include_in_conversion_count = models.BooleanField(blank=False, null=False, default=True)

我希望只有当new actual_start_date早于db中注册的actual_start_date时才能使用save()来更改actual_start_date。

所以我尝试更改了save和 init 方法:

    def __init__(self, *args, **kwargs):
        super(Placement, self).__init__(*args, **kwargs)
        if hasattr(self, 'actual_start_date'):
            self.__original_actual_start_date = self.actual_start_date
        if hasattr(self, 'actual_end_date'):
            self.__original_actual_end_date = self.actual_end_date

    def save(self, *args, **kwargs):
        if self.pk is None:
            super(Placement, self).save(*args, **kwargs)
        else:
            if hasattr(self, 'actual_start_date') & hasattr(self, '__original_actual_start_date'):
                self.actual_start_date = min(self.actual_start_date, self.__original_actual_start_date)
            if hasattr(self, 'actual_end_date') & hasattr(self, '__original_actual_end_date'):
                self.actual_end_date = max(self.actual_end_date, self.__original_actual_end_date)
            super(Placement, self).save(*args, **kwargs)

启动服务器时控制台中没有任何错误,我可以读取/更新/保存对象。但是,当我尝试测试它时,它不起作用。即使在旧对象后面有一个新的actual_start_date,也会保存该对象。

from sizmek_tag_manager.models import Placement
pl = Placement.objects.get(pk = 5473828)
pl.actual_start_date

返回datetime.date(2015,12,31)

pl.actual_start_date = datetime.date(2016, 1, 1)
pl.save()
pl = Placement.objects.get(pk = 5473828)
pl.actual_start_date 

返回datetime.date(2016,1,1)

那么我做错了什么?

2 个答案:

答案 0 :(得分:1)

如果您可以将现有对象与要保存的对象进行比较,为什么使用hasAttr?只需获取当前版本并检查新actual_start_date是否符合您的要求:

    class Placement(models.Model):
    #fields and other stuff

        def save(self, *args, **kwargs):
            if self.pk is not None:
                current = Placement.objects.get(pk=self.pk)

                #and here check the requirement
                if self.actual_start_date < current.actual_start_date:
                    super(Placement, self).save(*args, **kwargs)
                #else:
                #    raise exception or sth 

            else:
                super(Placement, self).save(*args, **kwargs)

答案 1 :(得分:-1)

问题的根本原因是提供类私有变量的双下划线。来自python 2 docs

  

具有双前导下划线的变量名称被“修改”以提供一种简单但有效的方法来定义类私有变量。表单__spam的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上用_classname__spam替换,其中classname是当前的类名,其中任何前导下划线都被剥离。

     

这不保证隐私:外部用户仍然可以故意访问“_classname__spam”属性,私有值在对象的 dict 中可见。许多Python程序员根本不打算使用私有变量名。

因此,解决方案将是

  1. 使用单个下划线变量名称

  2. 使用hasattr(Property, '_Property____original_actual_start_date'

  3. E.g:

    class Foo(object):
    
        def __init__(self, debug=False):
            self._foo = '_foo'
            self.__foo = '__foo'
            self.debug = debug
    
        def has_foo_property_with_prefix(self, prefix):
            property_name = ''.join([prefix, 'foo'])
            has_property = hasattr(self, property_name)
            if self.debug:
                print('has %s property? %s' % (property_name, has_property))
            return has_property
    
    if __name__ == '__main__':
        f = Foo(debug=True)
        assert True == f.has_foo_property_with_prefix('_')
        assert False == f.has_foo_property_with_prefix('__')
        assert True == f.has_foo_property_with_prefix('_Foo__')