1

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

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

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 休息框架时,我尝试修改视图集中的 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
4

2 回答 2

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)
于 2018-01-10T22:49:46.917 回答
0

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

我的一个直观方法是IntegerField按照 这样,该字段就会在创建时填充值。series_group_idcreated_add DateTimeFieldauto_now_addTruedatetime

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元组中。当您使用“全部”时,该字段将在您将其添加到模型后立即自动出现在您的字段中。

如果您需要更精细的控制,您可以像这样覆盖该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您当前正在跟踪的相应时间序列。

于 2017-12-18T11:18:06.857 回答