在反向关系上添加序列化程序 - Django Rest Framework

Posted

技术标签:

【中文标题】在反向关系上添加序列化程序 - Django Rest Framework【英文标题】:Add Serializer on Reverse Relationship - Django Rest Framework 【发布时间】:2016-05-19 01:18:28 【问题描述】:

我有一个Cart 模型和一个CartItem 模型。 CartItem 模型有一个 ForeignKeyCart 模型。

使用 Django Rest Framework 我有一个视图,API 用户可以在其中显示Cart,显然我想在响应中包含CartItem

我这样设置我的序列化器:

class CartSerializer(serializers.ModelSerializer):
    user = UserSerializer(read_only=True)
    cartitem_set = CartItemSerializer(read_only=True)
    class Meta:
        model = Cart
        depth = 1
        fields = (
            'id', 
            'user', 
            'date_created', 
            'voucher', 
            'carrier', 
            'currency', 
            'cartitem_set', 
        )

我的问题是第二行,cartitem_set = CartItemSerializer(read_only=True)

我收到 AttributeErrors 说 'RelatedManager' object has no attribute 'product'。 ('product' 是CartItem 模型中的一个字段。如果我从CartItemSerializer 中排除产品,我只会得到一个带有下一个字段的新 AttributeError ,我会报错。

我的猜测是,出于某种原因,Django REST 框架不支持添加序列化程序来反转这样的关系。我错了吗?我该怎么做?

PS

我之所以要使用CartItemSerializer(),是因为我想控制响应中显示的内容。

【问题讨论】:

试试cartitem_set = CartItemSerializer(read_only=True, many=True) 你的 CartItem 模型外键是什么样的? 【参考方案1】:

Ahmed Hosny 的回答是正确的。它需要将many 参数设置为True 才能工作。

CartSerializer 的最终版本如下所示:

class CartSerializer(serializers.ModelSerializer):
    cartitem_set = CartItemSerializer(read_only=True, many=True) # many=True is required
    class Meta:
        model = Cart
        depth = 1
        fields = (
            'id', 
            'date_created', 
            'voucher', 
            'carrier', 
            'currency', 
            'cartitem_set', 
        )

【讨论】:

我们可以将名称 caritem_set 更改为 items 吗? 您可以通过以下方式更改名称:items = CartItemSerializer(read_only=True, many=True, source='cartitem_set') 您可以从related_name 更改caritem_set 名称。在类 CartItem 中:cart = models.ForeignKey(Cart, related_name='items') ,然后在序列化程序中的“字段”中,您必须使用名称项目 是否可以使用这个解决方案然后过滤集合中返回的项目? 它的语法是什么样的?我目前已将源设置为 source='caritem_set' 以更改名称,但由于它是一个字符串,我将如何将过滤器或查询集传递给它?感谢您的帮助,马库斯。【参考方案2】:

在模型中定义相关名称并在序列化器关系中使用该相关名称很重要:

class Cart(models.Model):
   name = models.CharField(max_length=500)

class CartItem(models.Model):
   cart = models.ForeignKey(Cart, related_name='cart_items')
   items = models.IntegerField()

然后在您的序列化程序定义中使用这些确切的名称:

class CartSerializer(serializers.ModelSerializer):
    cart_items = CartItemSerializer(read_only=True)
    class Meta:
       model = Cart
       fields = ('name', 'cart_items',)

【讨论】:

这并没有解决问题。当我尝试使用cart_items = CartItemSerializer(read_only=True)时仍然得到'RelatedManager' object has no attribute 'product'错误 在原始问题中,他保留了隐含的相关名称:caritem_set 是的,这对于反向关系的工作非常重要【参考方案3】:

共享您的整个代码是明智的,即模型和序列化程序类。但是,也许这可以帮助调试您的错误,

我的序列化程序类

class CartItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = CartItem
        fields = ('id')

class CartSerializer(serializers.ModelSerializer):

    #take note of the spelling of the defined var
    _cartItems = CartItemSerializer()
    class Meta:
        model = Cart
        fields = ('id','_cartItems')

现在是模型

class CartItem(models.Model):
    _cartItems = models.ForeignKey(Subject, on_delete=models.PROTECT)
    #Protect Forbids the deletion of the referenced object. To delete it you will have to delete all objects that reference it manually. SQL equivalent: RESTRICT.
class Meta:
    ordering = ('id',)

class Cart(models.Model):
    class Meta:
    ordering = ('id',)

django-rest-framework中关系的详细概述,请参考他们的官方documentation

【讨论】:

以上是关于在反向关系上添加序列化程序 - Django Rest Framework的主要内容,如果未能解决你的问题,请参考以下文章

Django rest框架反向关系序列化器排除字段

序列化器关系 (Serializer relations)

序列化器关系 (Serializer relations)

Django 深度序列化 - 遵循反向外键约束

django admin - 选择反向外键关系(不创建,我想添加可用)

django rest 框架序列化程序中的关系数据库