使用perform_update

时间:2017-12-15 05:13:56

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

我们正在尝试实施时态数据库,以便我们能够跟踪所做的更改

我们所有型号都有以下字段

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休息?

是否有人能够指出正确的方向

以下是我的观看设置代码

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

2 个答案:

答案 0 :(得分:1)

我的问题的解决方案是使用字典数据进行FILTER和UPDATE。

 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)

答案 1 :(得分:0)

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

我的一个直观方法是实现额外的IntegerField被称为series_group_id的内容,它将作为分组时间序列的标识符和created_add {{ 1}} DateTimeField标志设置为auto_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) 方法。实际上,ModelSerializer提供了开箱即用的这种行为。您唯一需要做的就是将create添加到序列化程序的group_id元组中。当您使用“所有”时,只要您将字段添加到模型中,该字段就会自动显示在您的字段中。

如果您需要更精细的控制,可以覆盖fields方法,如下所示:

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)