python - 序列化器在 Django shell 中工作但在 View 中失败

标签 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通过其关联的 ServiceSerializer 创建一个新的 Service:我还必须传递一个完整的 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 中工作没有问题 - 创建过程中我必须只传递 ServiceCategoryid 而不是它的所有内容属性和新的 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 中传递,但在 View 中失败,并出现相同的 TypeError。

这是 View :

@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)

那么我做错了什么?

最佳答案

理解相关字段在序列化器中如何工作是一个常见问题。 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

关于python - 序列化器在 Django shell 中工作但在 View 中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41352395/

相关文章:

python - 我无法使用随机森林输出最佳选择的特征?

Python:如何判断我的 Python 是否具有 SSL?

python - 如何从 Django 中的一个字段引用不同的模型类型?

Django-rest-framework:从 .dispatch 返回响应

python - 用于 POST 请求的 Django 休息框架自定义过滤器

python - 下载完成后如何关闭浏览器?

Python:如何为程序创建积极的测试?

python - Django "Add a related_name argument to the definition"错误

database - Django 仅基于日期过滤日期时间

python - 根据 OpenApi 3 .yml 架构验证 DRF 响应