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

1bqhqjot  于 2023-05-01  发布在  Go
关注(0)|答案(8)|浏览(178)

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

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

lokaqttq

lokaqttq1#

在DRF版本3中。6.3这对我很有用

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

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

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

tkqqtvp1

tkqqtvp12#

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

q5iwbnjs3#

你可以做的另一件事是:

  • 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
j1dl9f46

j1dl9f464#

这对我来说很有效:

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

zfycwa2u5#

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

daolsyd06#

工作于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',)

使用 metaread_only_fields,我们可以准确地声明哪些字段应该是只读的。然后,我们需要在 metafields上声明foreign字段(最好像咒语一样显式:zen of python)。

8ehkhllq

8ehkhllq7#

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

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

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

sxpgvts38#

对于那些想要 * 替换 * ForeignKey(显示ID)的字段的用户,为了方便起见,您仍然可以使用__all__语法,并简单地覆盖您认为合适的字段名称。例如:

class MyModelSerializer(serializers.ModelSerializer):

    # override the category field that would otherwise show an integer value 
    # for the ID with the field of that model you choose. "name" here.
    category = serializers.ReadOnlyField(source='category.name')

    class Meta:
        model = MyModel
        fields = '__all__'

在我看来,这是很方便的B/c,你仍然可以使用__all__语法来捕获任何添加的字段。任何被覆盖的东西都是手动完成的,如果需要恢复,可以手动完成一些,而不需要更改任何其他语法。

相关问题