DRF SerializerMethodField如何传递参数

2024-10-03 09:18:03 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有办法将参数传递给Django Rest框架的SerializerMethodField

假设我有以下模型:

class Owner(models.Model):
    name = models.CharField(max_length=10)

class Item(models.Model):
    name = models.CharField(max_length=10)
    owner = models.ForeignKey('Owner', related_name='items')
    itemType = models.CharField(max_length=5) # either "type1" or "type2"

我需要的是返回一个包含以下字段的所有者JSON对象:name、type1items、type2items

我目前的解决方案是:

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Item
        fields = ('name', 'itemType')

class OwnerSerializer(serializers.ModelSerializer):
    type1items = serializers.SerializerMethodField(method_name='getType1Items')
    type2items = serializers.SerializerMethodField(method_name='getType2Items')

    class Meta:
        model = models.Owner
        fields = ('name', 'type1items', 'type2items')

    def getType1Items(self, ownerObj):
        queryset = models.Item.objects.filter(owner__id=ownerObj.id).filter(itemType="type1")
        return ItemSerializer(queryset, many=True).data

    def getType2Items(self, ownerObj):
        queryset = models.Item.objects.filter(owner__id=ownerObj.id).filter(itemType="type2")
        return ItemSerializer(queryset, many=True).data

这很有效。但是,如果我可以将一个参数传递给该方法,而不是使用两个几乎完全相同的代码的方法,那么会更干净。理想情况下,它将如下所示:

...
class OwnerSerializer(serializers.ModelSerializer):
    type1items = serializers.SerializerMethodField(method_name='getItems', "type1")
    type2items = serializers.SerializerMethodField(method_name='getItems', "type2")

    class Meta:
        model = models.Owner
        fields = ('name', 'type1items', 'type2items')

    def getItems(self, ownerObj, itemType):
        queryset = models.Item.objects.filter(owner__id=ownerObj.id).filter(itemType=itemType)
        return ItemSerializer(queryset, many=True).data

在文档SerializerMethodField accepts only one parameter中,它是method_name

是否有任何方法可以使用SerializerMethodField实现此行为?(此处的示例代码过于简化,因此可能存在错误。)


Tags: nameidmodelsfilteritemmethodclassqueryset
2条回答

基本字段无法执行此操作

您需要编写一个自定义序列化程序字段来支持它。下面是一个示例,您可能需要根据使用方式对其进行修改

此版本使用字段中的KWARG作为参数传递给函数。我建议您这样做,而不是使用*args,因为您将得到更合理的错误,并且在编写函数/字段定义时具有灵活性

class MethodField(SerializerMethodField):
    def __init__(self, method_name=None, **kwargs):
        # use kwargs for our function instead, not the base class
        super().__init__(method_name) 
        self.func_kwargs = kwargs

    def to_representation(self, value):
        method = getattr(self.parent, self.method_name)
        return method(value, **self.func_kwargs)

在序列化程序中使用字段:

class Simple(Serializer):
    field = MethodField("get_val", name="sam")
    def get_val(self, obj, name=""):
        return "my name is " + name

>>> print(Simple(instance=object()).data)
{'field': 'my name is sam'}

您可以重构现有的:

class OwnerSerializer(serializers.ModelSerializer):

    type1items = serializers.SerializerMethodField(method_name='getType1Items')
    type2items = serializers.SerializerMethodField(method_name='getType2Items')

    class Meta:
        model = models.Owner
        fields = ('name', 'type1items', 'type2items')

    def getType1Items(self, ownerObj):
        return getItems(ownerObj,"type1")

    def getType2Items(self, ownerObj):
        return getItems(ownerObj,"type2")

    def getItems(self, ownerObj, itemType):
        queryset = models.Item.objects.filter(owner__id=ownerObj.id).filter(itemType=itemType)
        return ItemSerializer(queryset, many=True).data

相关问题 更多 >