使用 django-rest-framework 序列化程序检索外键值

Posted

技术标签:

【中文标题】使用 django-rest-framework 序列化程序检索外键值【英文标题】:Retrieving a Foreign Key value with django-rest-framework serializers 【发布时间】:2013-06-21 05:27:24 【问题描述】:

我正在使用 django rest 框架来创建 API。 我有以下型号:

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __unicode__(self):
        return self.name


class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, related_name='items')

    def __unicode__(self):
        return self.name

为我要做的类别创建一个序列化程序:

class CategorySerializer(serializers.ModelSerializer):
    items = serializers.RelatedField(many=True)

    class Meta:
        model = Category

...这将为我提供:

['items': [u'Item 1', u'Item 2', u'Item 3'], u'id': 1, 'name': u'Cat 1',
 'items': [u'Item 4', u'Item 5', u'Item 6'], u'id': 2, 'name': u'Cat 2',
 'items': [u'Item 7', u'Item 8', u'Item 9'], u'id': 3, 'name': u'Cat 3']

我将如何从 Item 序列化程序中获取反向,即:

[u'id': 1, 'name': 'Item 1', 'category_name': u'Cat 1',
u'id': 2, 'name': 'Item 2', 'category_name': u'Cat 1',
u'id': 3, 'name': 'Item 3', 'category_name': u'Cat 1',
u'id': 4, 'name': 'Item 4', 'category_name': u'Cat 2',
u'id': 5, 'name': 'Item 5', 'category_name': u'Cat 2',
u'id': 6, 'name': 'Item 6', 'category_name': u'Cat 2',
u'id': 7, 'name': 'Item 7', 'category_name': u'Cat 3',
u'id': 8, 'name': 'Item 8', 'category_name': u'Cat 3',
u'id': 9, 'name': 'Item 9', 'category_name': u'Cat 3']

我已经阅读了 reverse relationships 上有关其余框架的文档,但这似乎与非反向字段的结果相同。我错过了什么明显的东西吗?

【问题讨论】:

你可以利用这个答案***.com/a/52491357/8536024 【参考方案1】:

在 DRF 3.6.3 版中,这对我有用

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name')

    class Meta:
        model = Item
        fields = ('id', 'name', 'category_name')

更多信息可以在这里找到:Serializer Fields core arguments

【讨论】:

但你必须小心,因为如果项目模型中的类别字段设置为空白=真,它应该抛出 NoneType 错误 @DesertCamel 您可以简单地将allow_null=True 添加到您的序列化器 CharField 以克服此问题【参考方案2】:

只使用相关字段而不设置many=True

注意,同样因为您希望输出名为category_name,但实际字段为category,您需要在序列化器字段上使用source 参数。

下面应该给你你需要的输出......

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.RelatedField(source='category', read_only=True)

    class Meta:
        model = Item
        fields = ('id', 'name', 'category_name')

【讨论】:

如何检索分类模型的所有字段?? 如果您想检索类别模型的所有字段,请制作类别序列化器并将其放在类似 category_name = CategorySerliazer() 的代码中 我尝试这样做,但我收到错误Relational field must provide a 'queryset' argument, or set read_only='True' 如果你想支持创建/更新,或者提供一个查询集属性,比如:category_name = serializers.RelatedField(source='category', queryset=Category.objects.all()) 我想。 如果你得到AssertionError:...,请使用这个答案***.com/a/44530606/5403449【参考方案3】:

您可以做的另一件事是:

在您的Item 模型中创建一个属性,该属性返回类别名称和 将其公开为ReadOnlyField

你的模型应该是这样的。

class Item(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, related_name='items')

    def __unicode__(self):
        return self.name

    @property
    def category_name(self):
        return self.category.name

您的序列化程序将如下所示。请注意,序列化程序将通过使用相同名称命名字段来自动获取 category_name 模型属性的值。

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField()

    class Meta:
        model = Item

【讨论】:

【参考方案4】:

这对我来说很好用:

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField(source='category.name')
    class Meta:
        model = Item
        fields = "__all__"

【讨论】:

【参考方案5】:

工作于 2018 年 8 月 8 日和 DRF 版本 3.8.2:

class ItemSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField(source='category.name')

    class Meta:
        model = Item
        read_only_fields = ('id', 'category_name')
        fields = ('id', 'category_name', 'name',)

使用元read_only_fields,我们可以准确地声明哪些字段应该是只读的。然后我们需要在 Meta fields 上声明 foreign 字段(最好是明确的口头禅:zen of python)。

【讨论】:

【参考方案6】:

简单的解决方案 source='category.name' 其中category 是外键,.name 是属性。

from rest_framework.serializers import ModelSerializer, ReadOnlyField
from my_app.models import Item

class ItemSerializer(ModelSerializer):
    category_name = ReadOnlyField(source='category.name')

    class Meta:
        model = Item
        fields = "__all__"

【讨论】:

【参考方案7】:

此解决方案更好,因为无需定义源模型。但是序列化器字段的名称应该与外键字段名称相同

class ItemSerializer(serializers.ModelSerializer):
    category = serializers.SlugRelatedField(read_only=True, slug_field='title')

    class Meta:
        model = Item
        fields = ('id', 'name', 'category')

【讨论】:

以上是关于使用 django-rest-framework 序列化程序检索外键值的主要内容,如果未能解决你的问题,请参考以下文章

断言错误:Django-rest-Framework

如何仅使用 django 作为后端并使用 django-rest-framework 发布

为啥使用 django-rest-framework 时不需要 `csrf_exempt`?

django-rest-framework 是不是提供管理站点来管理模型?

无法使用视图名称 (django-rest-framework) 解析超链接关系的 URL

django-rest-framework:如何序列化已经包含 JSON 的字段?