【问题标题】:Temporal Database with Django Rest Framework using perform_update使用 perform_update 的 Django Rest Framework 时态数据库
【发布时间】:2017-12-15 05:13:55
【问题描述】:

我们正在尝试实现一个临时数据库,以便我们能够跟踪所做的更改

我们所有的模型都有以下字段

vt = models.DateTimeField(db_column='VT', default=datetime(3000, 12, 31, 23, 00, 00, 000000))  # Value To
vflag = models.IntegerField(db_column='VFlag', default=1)  # Version Flag 1 = Current, 0 = Old   

在使用 Django rest 框架时,我尝试修改视图集中的 perform_update 以复制现有记录,进行更新,然后适当地设置时间字段。

当我有 1 条记录和第一次更新时它可以工作

但是,一旦我尝试进行第二次更新,它就会失败并创建更改的副本并覆盖第一条记录。

原记录

Currency = AUD, VFlag = 1, VT = time1

执行更新 - 成功

Currency = USD, VFlag = 1, VT = time2

Currency = AUD, VFlag = 0, VT = time1

下一次执行更新当前产生 - 失败

Currency = GBP, VFlag = 1, VT = time3

Currency = GBP, VFlag = 1, VT = time3

Currency = USD , VFlag = 0, VF = time2

预期的更新输出

Currency = GBP, VFlag = 1, VT = time3

Currency = USD, VFlag = 0, VT = time2

Currency = AUD, VFlag = 0, VT = time1

在 django rest 中是否可以使用时态数据库?

有没有人可以指出正确的方向

下面是我的视图集代码

class OptionMasterViewSet(viewsets.ModelViewSet):
serializer_class = OptionMasterSerializer
paginate_by = None
queryset = OptionMaster.objects.filter(vflag=1)
# queryset = OptionMaster.objects.all()

def get_queryset(self):
    queryset = OptionMaster.objects.filter(vflag=1)
    contractcode = self.request.query_params.get('contractcode', None)
    if contractcode is not None:
        queryset = queryset.filter(contractcode=contractcode, vflag=1)
    return queryset

def perform_update(self, serializer):

    changes = serializer.validated_data
    original_object = serializer.instance

    vt = datetime.now()

    changes['vf'] = vt

    #Build the old record
    old_record = {}
    for field in original_object._meta.get_fields():           
        old_record[field.name] = getattr(original_object, field.name)

    old_record['vflag'] = 0                
    old_record['vt'] = vt

    old_record = OrderedDict(old_record)

    #Save the new rrecord
    serializer.save()

    #Create the old record
    obj = OptionMaster.objects.create(**old_record)

    return serializer

我的序列化

class OptionMasterSerializer(TemporalModelSerializer):

class Meta:
    model = OptionMaster
    fields = '__all__'

潜在的时间序列化器

class TemporalHyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
vt = serializers.HiddenField(default=datetime(3000, 12, 31, 00, 00, 00, 000000))
vflag = serializers.HiddenField(default=1)

class TemporalModelSerializer(serializers.ModelSerializer):
vt = serializers.HiddenField(default=datetime(3000, 12, 31, 23, 00, 00, 000000))
vflag = serializers.HiddenField(default=1)

class TemporalModel(models.Model):
vt = models.DateTimeField(db_column='VT')  # Field name made lowercase.
vflag = models.IntegerField(db_column='VFlag')  # Field name made lowercase..
class Meta:
        abstract = True

【问题讨论】:

    标签: django django-rest-framework temporal-database


    【解决方案1】:

    我的问题的解决方案是使用字典数据进行过滤和更新。

     self.Meta.model.objects.filter(pk=instance.pk, vflag=1).update(**new_record)
    

    这是我下面最后的工作 TemporalModelSerializer

        class TemporalModelSerializer(serializers.ModelSerializer):
            vf = serializers.HiddenField(default=timezone.now())
            vt = serializers.HiddenField(default=datetime(3000, 12, 31, 23, 00, 00, 000000))
            vflag = serializers.HiddenField(default=1)
            vu = serializers.HiddenField(default='Theodore')
    
            class Meta:
                model = None
                fields = '__all__'
    
            def update(self, instance, validated_data):
    
                time_now = timezone.now()
    
                old_record = {}
                new_record = {}
    
                for (key, value) in validated_data.items():
                    old_record[key] = getattr(instance, key)
                    new_record[key] = validated_data[key]
                    setattr(instance, key, value)
    
                old_record['vt'] = time_now
                old_record['vflag'] = 0
                new_record['vf'] = time_now
    
                self.delete_me(old_record)
    
                self.Meta.model.objects.filter(pk=instance.pk, vflag=1).update(**new_record)
    
                return instance
    
            def delete_me(self, old_record):
                obj = self.Meta.model.objects.create(**old_record)
    

    【讨论】:

      【解决方案2】:

      Tbh,我以前从未处理过这样的问题,但这比 django-rest 更像是数据库设计问题。因此,在不了解这些模型的目的和关系的情况下,我只能做出估计(如下)。

      我的一种直观方法是实现一个额外的IntegerField,称为series_group_id,它将作为分组时间序列的标识符和created_addDateTimeFieldauto_now_add标志设置为True。这样一来,该字段在创建时将填充 datetime 值。

      class SomeModel(models.Model):
          # some other stuff like vflag and vt
          goup_id = models.IntegerField()
          created_at = models.DateTimeField(auto_now_add=True)
      

      此外,如果您要跟踪时间序列,从技术上讲,您并不是在更新您的实例,而是在创建新实例。因此,我的方法是将您的整个逻辑移至 create 方法。事实上,ModelSerializer 提供了这种开箱即用的行为。您唯一需要做的就是将group_id 添加到您的序列化程序的fields 元组中。当您使用“all”时,该字段将在您将其添加到模型后立即自动出现在您的字段中。

      如果您需要更精细的控制,您可以像这样覆盖create 方法:

      class OptionMasterViewSet(viewsets.ModelViewSet):
          serializer_class = OptionMasterSerializer
          paginate_by = None
          queryset = OptionMaster.objects.filter(vflag=1)
      
      
          def get_queryset(self):
              queryset = OptionMaster.objects.filter(vflag=1)
              contractcode = self.request.query_params.get('contractcode', None)
              if contractcode is not None:
                  queryset = queryset.filter(contractcode=contractcode, vflag=1)
              return queryset
      
          def create(self, request):
              data = request.get('data', None)
              serializer = self.serializer_class(data=data)
              serializer.is_valid(raise_exception=True)
      
              # some custom logic here in case you need it..
              self.perform_create(serializer)
              return Response({'detail': 'ok'}, status=status.HTTP_201_CREATED)
      

      限制

      这种方法期望到达的数据包含您当前正在跟踪的相应时间序列的group_id

      【讨论】:

      • 感谢您的贡献,我遇到了“finiteloopsoftware/django-bitemoral”实现的group_id方法。
      猜你喜欢
      • 2019-02-22
      • 1970-01-01
      • 2016-04-13
      • 1970-01-01
      • 2018-10-23
      • 2018-07-06
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      相关资源
      最近更新 更多