不要在Django中创建子对象

时间:2018-08-16 14:25:09

标签: python django serializer

我有一个表示Status的模型-并有一个来自Status模型的Object的外键。我希望能够创建新对象,但又不想允许创建更多Status条目(有一组5个预定义的条目已迁移到数据库中)。我相信我已经找到了如何以仅重用现有Status条目的方式构造序列化程序的方法,但是我不确定这是否是执行此类操作的最佳方法...

一些简化的代码:

class StatusSerializer(serializers.ModelSerializer):
    class Meta:
        model = Status
        fields = ('name',)

    def to_representation(self, obj):
        return obj.name

    def to_internal_value(self, data):
        return {
            'name': data
        }


class ObjectSerializer(serializers.ModelSerializer):

    status = StatusSerializer(read_only=True)

    class Meta:
        model = Object
        fields = ('obj_name', 'status',)

    def create(self, validated_data):
        # We do not want to create new statuses - only use existing ones
        status = Status.objects.get(name=self.initial_data['status'])
        return Object.objects.create(status=status, **validated_data)

    def update(self, instance, validated_data):

        instance.obj_name = validated_data.get('obj_name', instance.obj_name)

        # We do not want to create new statuses - only use existing ones
        instance.status = Status.objects.get(name=self.initial_data['status']) if 'status' in self.initial_data else instance.status

        return instance

如上所示,当显示Status对象时,我也将其展平-例如我将以下内容

{
    'obj_name': 'ObjectName',
    'status': {
        'name': 'StatusName'
    }
}

进入

{
    'obj_name': 'ObjectName',
    'status': 'StatusName'
}

这似乎很好用-但是我不确定如何处理API用户给我一个无效的Status名称的情况。现在,该API会冒泡从Status.DoesNotExist个请求中提出一个Status.objects.get(...)异常-我是否应该捕捉到该异常并重新引发序列化器/视图所期望的东西?

谢谢!

编辑:意识到我的问题并不十分清楚...

  1. 以上是否是禁止创建Status对象的一种好方法-并强制所有创建的Object将使用这些状态之一?
  2. 处理用户尝试使用无效的Object名称创建Status的情况的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

您可以在validate中使用ObjectSerializer方法。

class ObjectSerializer(serializers.ModelSerializer):

    status = StatusSerializer(read_only=True)

    class Meta:
        model = Object
        fields = ('obj_name', 'status',)

    def validate(self, attrs):
         validated_data = super().validate(attrs)
         status = self.initial_data.get('status')
         # Here assuming that None is not the valid value for status
         if status is not None:
             status_obj = Status.objects.filter(name=status)
             if not status_obj:
                 raise serializer.ValidationError('Invalid Status')
             status_obj = status_obj[0]
             validated_data['status'] = status_obj
        return validated_data

    # Nothing special to be done in create/update since we are sending data
    # in validated_data which will directly sent to the instance.

    # def create(self, validated_data):
        # We do not want to create new statuses - only use existing ones
        # status = Status.objects.get(name=self.initial_data['status'])
        #return Object.objects.create(status=status, **validated_data)

    #def update(self, instance, validated_data):

        # instance.obj_name = validated_data.get('obj_name', instance.obj_name)

        # We do not want to create new statuses - only use existing ones
        # instance.status = Status.objects.get(name=self.initial_data['status']) if 'status' in self.initial_data else instance.status

        # return instance

如果您可以使用不同的键来读写status,则可以像这样修改ObjectSerializer

class ObjectSerializer(serializer.ModelSerializer):
    status = serializer.SlugRelatedField(slug_field='name', queryset=Status.objects.all(), write_only=True)
    status_data = StatusSerializer(read_only=True, source='status')

    class Meta:
        model = Object
        fields = ('obj_name', 'status', 'status_data')

在这种情况下,如果您将{'obj_name': 'ObjectName', 'status': 'StatusName'}数据传递给序列化程序,则序列化程序将首先检查所提供查询集的StatusName字段中的name值(在这种情况下,使用all),如果无效则加注ValidationError。如果有效,则将status保存在实例的字段中。