serializer.is_valid() 适用于整数字段,但 serializer.save() 要求模型实例

serializer.is_valid() works with integer fields but serializer.save() asks for model instance

我在ma数据库中有一个多对多的关系(PK是整数)。我从数据库自动生成 django 模型并实现了最简单的序列化程序。

当我将带有整数的字典提供给序列化程序时,serializer.is_valid() returns 正确,但是 serializer.save() 表示字段应该是模型实例。

但是当我给出一个包含模型实例的字典时,serializer.is_valid() returns False.

data = {'tag_id': 9, 'spending_id': 17}
serializer = TagspendingSerializer(data= data)
serializer.is_valid()
True
serializer.save()

=> ValueError:无法分配“9”:"Tagspending.tag_id" 必须是 "Tag" 实例。

data = {'tag_id': Tag.objects.get(tag_id= 9), 'spending_id': Spending.objects.get(spending_id= 17)}
serializer = TagspendingSerializer(data= data)
serializer.is_valid()

=> 错误

这是我的模型:

class Tagspending(models.Model):
    tag_id = models.ForeignKey(Tag, models.DO_NOTHING, db_column='tag_ID', primary_key=True)
    spending_id = models.ForeignKey(Spending, models.DO_NOTHING, db_column='spending_ID')

    class Meta:
        managed = True
        db_table = 'TagSpending'
        unique_together = (('tag_id', 'spending_id'),)

这是我的序列化程序:

class TagspendingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tagspending
        fields = ('tag_id', 'spending_id')

由于您使用 tag_id 作为主键,因此 Django Rest Framework 似乎存在错误。 你应该改变你的模型,这是最好的做法,通过改变与 Tag 的关系作为 OneToOneField (因为它是一个主键,这种关系是唯一的,因此 OneToOneField 更配件)。你的序列化器应该可以工作了。

您还应该考虑重命名您的模型字段。无需引入 '_id' 后缀。

我想有些东西可以让你更清楚一点

Django 这样做:

ForeignKey defines an extra attribute with _id appended to the field name

您的模型中有以下字段:

tag_id = models.ForeignKey(Tag, models.DO_NOTHING, db_column='tag_ID', primary_key=True)

但您实际上并不需要指定数据库列或主键,而是这样做:

tag = models.ForeignKey(Tag, models.DO_NOTHING)

在 db 中,该字段的 db 列的名称为 tag_id(如您所愿),类型为整数。 这就是验证通过的原因。

现在,您可以访问 ID instance.tag_idinstance.tag.id(但是这两个调用之间存在差异 - 如果尚未检索到,则访问数据库)。

但是,在您的情况下 'tag_id' 是 ForeignKey 并且需要 "Tag" 个实例。

您有 2 种可能的方法来解决此问题(假设您使用我建议的更改来重命名该字段)

1) 您可以在 post 请求中使用 tag_id(现在,将字段名称更改为 tag

2) 在你的序列化器中,你可以指定以下内容:

tag = serializers.PrimaryKeyRelatedField(queryset=Tag.objects.all())

你可以用

做 post 请求
{"tag" : 1 } 

这会将您的 ID 解析为 Tag 实例(如果有效)