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


82

我正在使用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'}]

我已经阅读了有关其余框架的反向关系的文档,但这似乎与非反向字段的结果相同。我是否缺少明显的东西?

Answers:


82

只需使用相关字段而不进行设置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')

21
检索分类模型的所有领域该怎么办?
2014年

12
如果要检索类别模型的所有字段,请创建类别序列化程序,并将其放入类似category_name = CategorySerliazer()的代码中
Faizan Ali 2014年

7
我尝试执行此操作,但出现错误 Relational field must provide a 'queryset' argument, or set read_only='True'
ePascoal 2015年

或提供一个queryset属性(如果您想支持创建/更新),例如:category_name = serializers.RelatedField(source='category', queryset=Category.objects.all()) 我想。
stelios

1
如果您AssertionError:...使用此答案stackoverflow.com/a/44530606/5403449
Josh

82

在DRF版本3.6.3中,这对我有用

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

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

可以在这里找到更多信息:序列化器字段核心参数


但是您必须注意,如果“项目”模型中的类别字段设置为blank = True
Desert Camel,

29

您可以做的另一件事是:

  • 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通过使用相同名称命名字段来自动获取model属性的值。

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

    class Meta:
        model = Item

16

这对我来说很好:

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

9

在08/08/2018和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我们可以准确地声明哪些字段应为read_only。然后,我们需要foreign在Meta上声明该字段fields(随着口头禅的发展,最好是明确的:zen of python)。


5

一个简单的解决方案 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__"

0

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

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

    class Meta:
        model = Item
        fields = ('id', 'name', 'category')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.