Django REST框架:用于更新对象的序列化程序(如果存在)(通过唯一的一起)

时间:2018-04-25 09:19:08

标签: python django django-rest-framework django-serializer

我有模型运行。它代表数据的时间段测量:

class Run(models.Model):
    start_time      = models.DateTimeField(db_index=True)
    end_time        = models.DateTimeField()
    chamber         = models.ForeignKey(Chamber, on_delete=models.CASCADE)

    class Meta:
        unique_together=(('start_time', 'chamber'),)

以下是此端点的POST请求数据模糊示例:

{
    "start_time": "2018-11-11T12:00:00Z",
    "end_time": "2018-11-11T12:00:01Z",
    "chamber": "My Test Chamber"
}

运行属于商会,并且 start_time end_time

运行无法共享相同的商会 start_time 。如果我在请求数据模糊中获得相同的 start_time 商会,则表示运行仍在进行中,需要进行更新。

当请求第一次出现时,我创建了一个运行对象,该工作正常。发送请求的传感器将发送相同的POST请求数据模糊,只更改数据模糊的 end_time ,只要“运行”正在进行即可。

传感器不发送PUT或PATCH,它只发送POST,这可能是一个问题,但它是不可修复的,所以我必须处理POST请求。

我想要的行为是:

  1. 第一次发送运行数据模糊时,请创建一个新的运行对象
  2. 只要我在数据模糊中收到相同的商会 run_start ,(检查此组合是否存在),请更新运行 end_time 运行正在进行中)
  3. 这是Serializer:

    class RunsCreateSerializer(ModelSerializer):
        class Meta:
            model = Run
            fields = [
                'id',
                'chamber',
                'start_time',
                'end_time'
            ]
    

    这是API端点上的views.py:

    class RunsCreateAPIView(CreateAPIView):
        queryset = Run.objects.all()
        queryset = queryset.prefetch_related('chamber')
        serializer_class = RunsCreateSerializer
        permission_classes = [IsAuthenticated]
    
        def create(self, request, *args, **kwargs):
            try:
                chamber = Chamber.objects.get(chamber_name=request.data["chamber"])
                request.data["chamber"] = chamber.id
            except:
                print("Invalid chamber name")
    
            serializer = RunsCreateSerializer(data=request.data)
            print(serializer)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.errors)
    

    现在,我发现我必须稍微修改views.py上的“创建”,因为传感器将 Chamber 作为字符串标识符发送。然后,我必须检查该 Chamber 表中的字符串并检索对象实例,然后修改请求数据,将 Chamber 字符串替换为我的数据库中的ID。我不确定这是否是正确的方法,但它对我有用。

    现在我试图解决这个问题:

    在serializers.py上:

    def create(self, validated_data):
        run, created = Run.objects.update_or_create(
                        chamber=validated_data.get('chamber'),
                        start_time=validated_data.get('start_time'),
                        end_time=validated_data.get('end_time'))
        return run
    
    def update(self, run, validated_data):
        run.chamber = validated_data.get('chamber', run.chamber)
        run.start_time = validated_data.get('start_time', run.start_time)
        run.created = validated_data.get('created', run.created)
        run.save()
        return run
    

    我想通过在我的序列化程序上执行此操作,我可以更新对象,但它似乎没有达到这一点(在创建和更新方法上尝试使用print(“完整性检查”),I看不到我的理智检查输出,所以我知道我没有达到这一点。)

    我怀疑它与我重写视图上的create方法,但我不确定。

    如果您知道如何更新对象,并且可能让序列化程序/视图处理 Chamber 名称的字符串,而不必插入替换ID字符串的方法,我将非常感谢您帮助

2 个答案:

答案 0 :(得分:1)

正如您提到的那样,您将chamber作为字符串,因此要正确处理该关系,请在序列化程序中使用chamber = serializer.StringRelatedField()。删除在序列化器/视图中覆盖的所有方法。只需在您的RunsCreateAPIView中添加以下内容即可。

def perform_create(self, serializer):
    chamber=serializer.validated_data.get('chamber'),
    start_time=serializer.validated_data.get('start_time')
    end_time=serializer.validated_data.get('end_time')
    Run.objects.update_or_create(
                  chamber=chamber, 
                  start_time=start_time, 
                  defaults = {"end_time": end_time}
                  )

update_or_create将根据chamber和start_time的值自动处理创建或更新。

答案 1 :(得分:0)

我们可以简单地覆盖方法def perform_create(self, serializer):

class RunsCreateAPIView(CreateAPIView):
  # some code
  def perform_create(self, serializer):
    chamber=serializer.validated_data.get('chamber'),
    chamber = Chamber.objects.get(chamber_name=chamber)
    start_time=serializer.validated_data.get('start_time')
    end_time=serializer.validated_data.get('end_time'),

    obj_lst = Run.objects.filter(chamber=chamber, start_time=start_time)
    if obj_lst:
        obj_lst.update(
                chamber=chamber,
                start_time=start_time,
                end_time=end_time)
    else:
        Run.objects.create(chamber=chamber,
                start_time=start_time,
                end_time=end_time)