【问题标题】:Django REST - Incorrect type. Expected pk value, received str (pk is a CharField)Django REST - 类型不正确。预期的 pk 值,收到的 str(pk 是一个 CharField)
【发布时间】:2020-09-09 18:36:51
【问题描述】:

我有一个ModelSerializer,我用它来创建新帖子。它有一个字段book,类型为PrimaryKeyRelatedField(queryset=Book.objects.all(), pk_field=serializers.CharField(max_length=255))

当我发布到此端点时,我收到错误:

{
    "book": ["Incorrect type. Expected pk value, received str."] 
}

这怎么可能,因为我的主键是 CharField。

真正让我失望的是,我尝试用SlugRelatedField 绕过这个问题,但是当我这样做时,我得到了一个非常长而且奇怪的错误: DataError at /api/content/posts/ value "9780241470466" is out of range for type integer LINE 1: ...020-05-22T20:14:17.615205+00:00'::timestamptz, 1, '978024147...,我完全看不懂,因为我没有设置整数。

序列化代码:

class PostCreationSerializer(serializers.ModelSerializer):
    book = serializers.PrimaryKeyRelatedField(queryset=Book.objects.all(), pk_field=serializers.CharField(max_length=255))

    class Meta:
        model = Post
        fields = ['content', 'book', 'page', 'date_posted', 'user', 'id']
        read_only_fields = ['date_posted', 'user', 'id']

型号代码:

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=100)
    pages = models.PositiveSmallIntegerField(null=True, blank=True)

    image = models.URLField(null=True, blank=True)
    date_published = models.CharField(max_length=4, null=True, blank=True)
    publisher = models.CharField(max_length=140, null=True, blank=True)
    isbn13 = models.CharField(max_length=13, primary_key=True)

    objects = AutomaticISBNDBManager

    def __str__(self):
        return self.title

查看代码:

class PostListCreate(UseAuthenticatedUserMixin, generics.ListCreateAPIView):
    serializer_class = PostSerializer
    queryset = Post.objects.order_by('-date_posted')

    def get_serializer_class(self):
        if self.request.method == 'POST':
            return PostCreationSerializer
        else:
            return PostSerializer

编辑:我发送的 POST:

{
  "book": "9780241470466",
  "content": "test",
  "page": "10"
}

注意:user 和 date_posted 是自动设置的。

【问题讨论】:

  • 您能分享您的发帖数据吗?您是否使用id 字段作为主键?
  • @kamilyrb isbn13 是主键。我将使用我发布的数据编辑问题
  • 您是否覆盖了AutomaticISBNDBManager 中的任何方法?无法使用默认管理器重现此错误。
  • @drec4s 是的,我已经覆盖了 get() 方法。它尝试使用普通的 get 方法,如果失败,它会创建一本新书并返回它。
  • @drec4s 虽然对我来说自定义和标准管理器都会发生这种情况。也许是因为 Postgres。

标签: python django postgresql django-rest-framework


【解决方案1】:

所以,我并没有真正解决它,但我找到了解决问题的方法:

我使用 PostgreSQL 作为数据库后端。这些问题似乎来自我选择使用自定义主键,或者因为我的自定义主键是 CharField。幸运的是,我在进行这些更改之前进行了数据库备份,因为我不确定一切是否顺利,我将代码恢复为使用 id 作为主键并使用 SlugRelatedField 来获取这本书。

所以,解决方案是:Postgres 不喜欢 CharField 作为主键?

【讨论】:

    【解决方案2】:

    您可以像这样使用SlugRelatedField 而不是PrimaryKeyRelatedField

    book = serializers.SlugRelatedField(
    slug_field='isbn13',
    queryset=Book.objects.all()
    )
    

    来自文档:

    SlugRelatedField 可用于使用目标上的字段来表示关系的目标。

    • 对于另一种方法,您可以在序列化程序validate 方法中将书籍引用设置为您的帖子模型:

    1-) 将 PrimaryKeyRelatedField 替换为 CharField

    2-) 在您的 validate 方法中查找 book 对象并将其分配给经过验证的数据。

    class PostCreationSerializer(serializers.ModelSerializer):
        book = serializers.CharField()
    
        class Meta:
            model = Post
            fields = ['content', 'book', 'page', 'date_posted', 'user', 'id']
            read_only_fields = ['date_posted', 'user', 'id']
    
        def validate(self, attrs):
            try:
                attrs['book'] = Book.objects.get(isbn13=attrs['book'])
                return attrs
            except Book.DoesNotExist:
                raise serializers.ValidationError("Book not found")
    

    【讨论】:

    • 已经尝试并得到了一个不同的错误:“真正让我失望的是,我尝试使用 SlugRelatedField 来规避这个问题,但是当我这样做时,我得到了一个非常长且奇怪的错误: /api/content/posts/ 值“9780241470466”处的 DataError 超出类型整数 LINE 1 的范围:...020-05-22T20:14:17.615205+00:00'::timestamptz, 1, '978024147.. .,我根本不明白,因为我没有设置整数。” (见原帖)
    • @Bruce 我建议了另一种方法。真的我不明白你为什么会收到这个错误。我希望这种替代方法对您有用。
    • 这会引发与我尝试 PrimaryKeyRelated 时相同的错误。我现在试试,如果我把主键改回“id”会怎样
    猜你喜欢
    • 2015-08-26
    • 2021-09-06
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-05-17
    • 2021-10-11
    • 2017-06-14
    • 1970-01-01
    相关资源
    最近更新 更多