如何使用自引用递归字段在 DRF 串行器中进行过滤

Pro*_*eus 4 python django python-3.x django-rest-framework

使用 Python 3.x 和 Django Rest 框架。我有一个带有Recursive Field (自身)的序列化器,它按预期工作。但是,我需要一种方法来最初过滤它返回的嵌套子项active = True

我尝试了不同的方法来通过active=True过滤子项,但我无法在序列化器中返回的嵌套子项上使用此方法。

这是我所拥有的。

class MenuListSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='menu_detail')
    children = RecursiveField(many=True, required=False)


class RecursiveField(serializers.Serializer):
    """
    Self-referential field for MPTT.
    """
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data
Run Code Online (Sandbox Code Playgroud)

这是我尝试过的方法,但出现错误ListSerializer' object has no attribute 'queryset'但是,我什至不确定这是否有效。

class MenuListSerializer(serializers.ModelSerializer):

    def __init__(self, *args, request_user=None, **kwargs):
        # try and filter active in chrildrend before query set is passed
        super(MenuListSerializer, self).__init__(*args, **kwargs)
        # print(self.fields['children'].parent)
        self.fields['children'].queryset =     self.fields['children'].queryset.filter(active=True)

    url = serializers.HyperlinkedIdentityField(view_name='menu_detail')
    children = RecursiveField(many=True, required=False)
Run Code Online (Sandbox Code Playgroud)

Mic*_*oni 5

如果我理解得很好,您正在尝试Menu以分层方式序列化对象。为此,我想您会递归地序列化顶级菜单对象,不是吗?(否则您将获得顶层的所有菜单对象)。

为了能够仅过滤活动的子项,我建议active_children在您的模型上创建一个属性:

class Menu(MPTTModel, TimeStampedModel):
    name = models.CharField(max_length=100)
    active = models.BooleanField(default=1)
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children')

    @property
    def active_children(self):
        return self.children.filter(active=True)
Run Code Online (Sandbox Code Playgroud)

然后您可以将其用作children序列化器中字段的来源:

class MenuListSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='menu_detail')
    children = RecursiveField(many=True, required=False, source='active_children')
Run Code Online (Sandbox Code Playgroud)

现在,序列化时应该只有活动的子级。

请注意,您还应该过滤查询集中的顶级对象,因为上面的过滤仅适用于Menu对象中的子对象。