简体   繁体   English

DRF SerializerMethodField如何传递参数

[英]DRF SerializerMethodField how to pass parameters

Is there a way to pass paremeters to a Django Rest Framework's SerializerMethodField?有没有办法将参数传递给 Django Rest 框架的 SerializerMethodField?

Assume I have the models:假设我有模型:

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"

What I need is to return an Owner JSON object with the fields: name, type1items, type2items.我需要的是返回一个所有者 JSON object 字段:名称,type1items,type2items。

My current solution is this:我目前的解决方案是这样的:

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

This works.这行得通。 But it would be much cleaner if I could pass a parameter to the method instead of using two methods with almost the exact code.但是,如果我可以将参数传递给该方法,而不是使用几乎完全相同的代码的两个方法,那将会更加简洁。 Ideally it would look like this:理想情况下,它看起来像这样:

...
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

In the docs SerializerMethodField accepts only one parameter which is method_name .在文档中SerializerMethodField 只接受一个参数,即method_name

Is there any way to achieve this behaviour using SerializerMethodField?有没有办法使用 SerializerMethodField 实现这种行为? (The example code here is overly simplified so there might be mistakes.) (此处的示例代码过于简化,因此可能存在错误。)

There is no way to do this with the base field.没有办法用基本字段来做到这一点。

You need to write a custom serializer field to support it.您需要编写一个自定义序列化器字段来支持它。 Here is an example one, which you'll probably want to modify depending on how you use it.这是一个示例,您可能需要根据自己的使用方式对其进行修改。

This version uses the kwargs from the field to pass as args to the function.此版本使用来自现场的 kwargs 作为 args 传递给 function。 I'd recommend doing this rather than using *args since you'll get more sensible errors, and flexibility in how you write your function/field definitions.我建议这样做而不是使用*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)

Using the field in a serializer:使用序列化程序中的字段:

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'}

You could just refactor what you have:你可以重构你所拥有的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM