Serializer在Django shell中工作,但在视图中失败

时间:2016-12-27 21:25:19

标签: python django django-rest-framework

我有这些模特:

class ServiceCategory(models.Model):
    class Meta:
        db_table = 'service_categories'

    category = models.CharField(max_length=24)

    def __str__(self):
        return self.category


class Service(models.Model):
    class Meta:
        db_table = 'services'

    service = models.CharField(max_length=24)
    category = models.ForeignKey('ServiceCategory')

    def __str__(self):
        return self.service

他们的序列化器:

class ServiceCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = ServiceCategory
        fields = ('id', 'category')

class ServiceSerializer(serializers.ModelSerializer):
    category = ServiceCategorySerializer()

    class Meta:
        model = Service
        fields = ('id', 'service', 'category')

完成此设置后,I quickly bumped into a problem通过其关联的Service创建新的ServiceSerializer:我必须传递一个完整的ServiceCategory及其所有字段,即使我只需要它的id。上面的ServiceCategory看起来很简单,但事实并非如此,因为为了简洁,我省略了很多其他字段。

因此,将ServiceCategory的完整属性传递到前端的表单对我来说似乎非常低效,所以我尝试了另一种方法:

class UpsertServiceSerializer(serializers.ModelSerializer):
    category = serializers.IntegerField() # not ServiceCategorySerializer()

    class Meta:
        model = Service
        fields = ('service', 'category')

    def create(self, data):
        c = ServiceCategory.objects.get(pk=data['category'])
        return Service.objects.create(service=data['service'], category=c)

我的目的是使用UpsertServiceSerializer进行创建和更新,现在ServiceSerializer用于读取。 UpsertServiceSerializer在Django shell中没有遇到任何问题 - 创建通过我只需传递id ServiceCategory而不是所有属性和新Service对象确实已添加到数据库中 - 但是当我通过Postman发出POST请求时,我收到此错误:

TypeError at /services 
int() argument must be a string, a bytes-like object or a number, not 'ServiceCategory'

所以我尝试了UpsertServiceSerializer的新版本:

class UpsertServiceSerializer(serializers.Serializer):
    service = serializers.CharField()
    category = serializers.IntegerField()

    def create(self, data):
        c = ServiceCategory.objects.get(pk=data['category'])
        return Service.objects.create(service=data['service'], category=c)

请注意,在新版本中,我对serializers.Serializer进行了子类化,而不是serializers.ModelSerializer,并且其中没有class Meta。这个版本没有什么不同,它也传入Django shell,但在具有相同TypeError的视图中失败。

以下是观点:

@api_view(['GET', 'POST'])
def services(request):
    if request.method == 'GET':
        services = Service.objects.all()
        serializer = ServiceSerializer(services, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = UpsertServiceSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

那么我做错了什么?

1 个答案:

答案 0 :(得分:1)

了解相关字段在序列化程序中的工作方式是常见问题。 ForeignKey默认使用PrimaryKeyRelatedField,因此您不需要IntegerField,即使您不需要覆盖create方法。

class UpsertServiceSerializer(serializers.ModelSerializer):

    class Meta:
        model = Service
        fields = ('service', 'category')

传递pk类别只会有效。如果您需要category模型的特殊布局而不是普通pk,则可以编写自己的to_representation方法。

 class UpsertServiceSerializer(serializers.ModelSerializer):
     ...
     def to_representation(self, instance):
         representation = super(UpsertServiceSerializer, self).to_representation(instance)
         representation['category'] = ServiceCategorySerializer(instance.category).data
         return representation