Django serializer.data包含不存在的值

时间:2019-04-24 13:04:16

标签: python django django-rest-framework

上下文

我有一个API端点,用于设备执行签入。

未知设备时:

  • 创建了一个新的CustomerDevice实例
  • 已创建与新创建的DeviceStatus相关的新CustomerDevice实例

API响应:

{
    "customer_device_uuid": "646aaff6-debf-4281-bd7f-064dd6dc8ab8",
    "device_group": {
        "group_uuid": "ebd0990b-aeb5-46a4-9fad-82237a5a5118",
        "device_group_name": "Default",
        "color": "4286f4",
        "is_default": true
    }
}

已知设备时

  • 创建了一个新的DeviceStatus实例,该实例与发出请求的设备有关。

API响应:

{
    "customer_device_uuid": "fbbdf1d1-766d-40a9-961f-2c5a5cb3db6e"
}

问题

问题是已知设备执行签入时的API响应。返回的customer_device_uuid在数据库中不存在,看起来像是随机生成的uuid

我希望已知设备的API响应与未知设备的API响应相同。

serializer.data包含随机uuid,直到else语句为止。 serializer.data从那里包含我在响应中所需的数据。

我试图在self.perform_create块中调用if。这导致serializer.data具有正确的响应数据。但是,无论设备是已知设备还是未知设备,这都会为每次签入创建一个新的CustomerDevice和相关的DeviceStatus

我的views.py

class DeviceCheckinViewSet(viewsets.ModelViewSet):
    serializer_class = CheckinSerializer
    queryset = CustomerDevice.objects.all()
    http_method_names = 'post'

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # if the device is known -> just log the data
        if CustomerDevice.objects.filter(device_id_android=serializer.validated_data['device_id_android']).exists():
            self.log_device_status(request)
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

        # if device is not known -> link it to the customer and log the device data
        else:
            self.perform_create(serializer)
            customer_device = CustomerDevice.objects.get(device_id_android=request.data['device_id_android'])
            DeviceStatus.objects.create(
                customer_device_id=customer_device.customer_device_uuid,
                disk_space=request.data['disk_space'],
                battery_level=request.data['battery_level'],
                battery_cycles=request.data['battery_cycles'],
                battery_health=request.data['battery_health']
            )
            headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    # creates new instance with default group
    def perform_create(self, serializer):
        serializer.save(group_uuid=get_default_group())


    def log_device_status(request):
        DeviceStatus.objects.create(
            customer_device_id=request.data['customer_device_uuid'],
            disk_space=request.data['disk_space'],
            battery_level=request.data['battery_level'],
            battery_cycles=request.data['battery_cycles'],
            battery_health=request.data['battery_health']
        )

我的serializers.py

class DeviceGroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = DeviceGroup
        fields = ('group_uuid', 'device_group_name', 'color', 'is_default')


class CheckinSerializer(serializers.ModelSerializer):
    device_group = DeviceGroupSerializer(many=False, read_only=True, source='group_uuid')

    class Meta:
        model = CustomerDevice
        fields = ('customer_device_uuid', 'customer_uuid', 'device_id_android', 'device_group')
        extra_kwargs = {
            'customer_uuid': {'write_only': True},
            'device_id_android': {'write_only': True}
        }

所需结果

已知或未知设备时,以下API响应。

{
    "customer_device_uuid": "646aaff6-debf-4281-bd7f-064dd6dc8ab8",
    "device_group": {
        "group_uuid": "ebd0990b-aeb5-46a4-9fad-82237a5a5118",
        "device_group_name": "Default",
        "color": "4286f4",
        "is_default": true
    }
}

编辑

DeviceGroupSerializer()添加到了serializers.py

相关models.py

# Customer table
class Customer(models.Model):
    customer_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    customer_name = models.CharField(max_length=128, unique=True)
    users = models.ManyToManyField('auth.User', related_name='customers')

    def __str__(self):
        return self.customer_name

    class Meta:
        db_table = 'customer'


# Device group table
class DeviceGroup(models.Model):
    group_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    customer_uuid = models.ForeignKey(Customer, on_delete=models.DO_NOTHING)
    device_group_name = models.CharField(max_length=20)
    color = models.CharField(max_length=8)
    is_default = models.BooleanField(default=False)

    def __str__(self):
        return self.device_group_name

    class Meta:
        db_table = 'device_group'


# Customer_device table
class CustomerDevice(models.Model):
    customer_uuid = models.ForeignKey(Customer, on_delete=models.CASCADE)
    customer_device_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    group_uuid = models.ForeignKey(DeviceGroup, null=True, blank=True, on_delete=models.SET(get_default_group))
    device_id_android = models.CharField(max_length=100, blank=True, null=True)  # generated by client

    def __repr__(self):
        return '%r' % self.customer_device_uuid

    class Meta:
        db_table = 'customer_device'
        unique_together = (('customer_uuid', 'customer_device_uuid'),)  # composite key


# Device status table
class DeviceStatus(models.Model):
    device_status_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    disk_space = models.PositiveIntegerField(blank=True, null=True)
    battery_level = models.PositiveIntegerField(blank=True, null=True)
    battery_health = models.CharField(max_length=30)
    battery_cycles = models.PositiveIntegerField(blank=True, null=True)
    customer_device = models.ForeignKey(CustomerDevice, on_delete=models.CASCADE, related_name="customer_device")

    def __repr__(self):
        return '%r' % self.device_status_uuid

    class Meta:
        db_table = 'device_status'

1 个答案:

答案 0 :(得分:1)

我已实例化了一个uuid为Customer的{​​{1}}和一个e73141ab-883c-44bc-8ce2-21b492cab03e设置为DeviceGroup的{​​{1}},以便is_default可以对其进行分配。

现在发生的是,当我使用以下命令调用端点时:

True

产生的响应是:

get_default_group

这正是您所需要的。我的假设是您的{ "customer_uuid": "e73141ab-883c-44bc-8ce2-21b492cab03e", "customer_device_uuid": "444b944a-4bcf-4ea2-8860-1d3ca82fd1d3", "device_id_android": "111", "disk_space": 10, "battery_level": 10, "battery_health": "good", "battery_cycles": 10 } 没有返回默认组。

第二次您的序列化程序没有产生您想要的输出的原因是因为您正在序列化请求数据而不是实例,并且在请求数据中没有{ "customer_device_uuid": "0d53c7d4-ce34-42ce-9dd8-5e7ea07c4438", "device_group": { "group_uuid": "5ee2f30e-bfd1-4f31-83ad-753d1d7220ad", "device_group_name": "", "color": "", "is_default": true } } ,因此您需要请执行以下操作:

get_default_group