Django REST Framework:序列化程序以更新对象(如果存在)(通过唯一一起)
Django REST Framework: Serializer to update object if it exists (by unique together)
我有型号 运行。它代表数据的一个时间段测量:
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"
}
一个运行属于一个Chamber并且有一个start_time 和 end_time
A 运行 不能共享同一个 Chamber 和 start_time.如果我在请求数据 blurb 中得到相同的 start_time 和 Chamber,这意味着 运行仍在进行中,需要更新。
第一次收到请求时,我创建了一个 运行 对象,效果很好。发送请求的传感器随后将发送相同的 POST 请求数据 blurb,仅更改数据 blurb 的 end_time,只要“运行”正在进行中。
传感器不发送 PUT 或 PATCH,它只发送 POST,这可能是个问题,但无法修复,所以我不得不凑合着 POST 请求。
我想要的行为是:
- 第一次发送运行数据blurb,创建一个新的运行对象
- 只要我在数据简介中收到相同的 Chamber 和 run_start,(检查此组合是否存在), 更新 运行 的 end_time (a 运行 进行中)
这是序列化程序:
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 上的“create”,因为传感器发送 Chamber 作为字符串标识符。然后我必须根据我的 Chambers table 检查该字符串并检索对象实例,然后修改请求数据以替换 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("Sanity check")方法,我没有看到我的健全性检查输出,所以我知道我没有达到那个点)。
我怀疑这与我重写视图上的创建方法有关,但我不确定。
如果您知道如何更新对象,并且可能让 serializer/view 处理 Chamber 名称的字符串,而不必干预替换字符串的方法ID,非常感谢你的帮助。
我们可以简单地覆盖方法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)
正如您提到的,您正在获取 chamber
作为字符串,因此要正确处理该关系,请在序列化程序中使用 chamber = serializer.StringRelatedField()
。删除您在 serializer/view 中覆盖的任何方法。只需在 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.
我有型号 运行。它代表数据的一个时间段测量:
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"
}
一个运行属于一个Chamber并且有一个start_time 和 end_time
A 运行 不能共享同一个 Chamber 和 start_time.如果我在请求数据 blurb 中得到相同的 start_time 和 Chamber,这意味着 运行仍在进行中,需要更新。
第一次收到请求时,我创建了一个 运行 对象,效果很好。发送请求的传感器随后将发送相同的 POST 请求数据 blurb,仅更改数据 blurb 的 end_time,只要“运行”正在进行中。
传感器不发送 PUT 或 PATCH,它只发送 POST,这可能是个问题,但无法修复,所以我不得不凑合着 POST 请求。
我想要的行为是:
- 第一次发送运行数据blurb,创建一个新的运行对象
- 只要我在数据简介中收到相同的 Chamber 和 run_start,(检查此组合是否存在), 更新 运行 的 end_time (a 运行 进行中)
这是序列化程序:
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 上的“create”,因为传感器发送 Chamber 作为字符串标识符。然后我必须根据我的 Chambers table 检查该字符串并检索对象实例,然后修改请求数据以替换 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("Sanity check")方法,我没有看到我的健全性检查输出,所以我知道我没有达到那个点)。
我怀疑这与我重写视图上的创建方法有关,但我不确定。
如果您知道如何更新对象,并且可能让 serializer/view 处理 Chamber 名称的字符串,而不必干预替换字符串的方法ID,非常感谢你的帮助。
我们可以简单地覆盖方法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)
正如您提到的,您正在获取 chamber
作为字符串,因此要正确处理该关系,请在序列化程序中使用 chamber = serializer.StringRelatedField()
。删除您在 serializer/view 中覆盖的任何方法。只需在 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.