无法重载(重写)DRF序列化程序的save()方法(或其他方法)

2024-10-01 17:25:01 发布

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

我试图重写序列化程序的save()方法(as per the docs)以支持批量实例创建。目前,我有一些类似这样的东西(如果你愿意,跳过代码,这只是为了上下文。真正的问题是我不能创建任何自己的序列化程序方法)。在

在序列化程序.py

class BulkWidgetSerializer(serializers.ModelSerializer):
    """ Serialize the Widget data """

    #http://stackoverflow.com/questions/28200485/
    some_foreign_key = serializers.CharField(source='fk_fizzbuzz.name', read_only=False)

    class Meta:
        model = Widget
        fields = (
            'some_foreign_key',
            'uuid',
            'foobar',
        )
        # Normally we would set uuid to read_only, but then it won't be available in the self.validate()
        # method. We also need to take the validator off this field to remove the UNIQUE constraint, and
        # perform the validation ourselves.
        # See https://github.com/encode/django-rest-framework/issues/2996 and
        # https://stackoverflow.com/a/36334825/3790954
        extra_kwargs = {
            'uuid': {'read_only': False, 'validators': []},
        }

    def validate(self, data):
        return super(WidgetSerializer, self).validate(self.business_logic(data))

    def save(self):
        print("---------Calling save-----------")
        more_business_logic()
        instances = []
        for widget in self.validated_data:
            instances.append(Widget(**self.validated_data))
        Widget.objects.bulk_create(instances)
        return instances

在视图集.py

^{pr2}$

然后我在数据库中获得新的Wiget实例,但是它们的属性表明more_business_logic()中的more_business_logic()调用没有发生。但是,我确实得到反馈,表明business_logic中的business_logic发生了调用。在

从这一点上,我推测我仍然坚持使用super类的save()?如何重写此方法?在

编辑:

当我在两个文件中将save()重命名为newsave(),并尝试在视图集中调用它时,我得到:

AttributeError: 'ListSerializer' object has no attribute 'newsave'

怎么回事?在断点处用pdb进行检查表明它确实是一个BulkWidgetSerializer。在shell中检查表明newsave绝对是该类的一个方法:

>>>'newsave' in [func for func in dir(BulkWidgetSerializer) if callable(getattr(BulkWidgetSerializer, func))]
True

此外,如果我在序列化程序类中创建自己的测试方法:

def test_method(self):
    print("Successful test method")

我也不能这么说!在

>>> serializer.test_method()
AttributeError: 'ListSerializer' object has no attribute 'test_method'

Tags: theinstances方法inself程序data序列化
3条回答

您的BulkWidgetSerializerListSerializer包装,这是DRF的默认行为。这就是为什么你的新方法不见了。在

如果用kwarg many=Truethe library wraps it实例化{}的任何子类,并将child设置为您的Serializer类。在

因此,您无法重写save()方法以获得所需的效果。 尝试重写序列化程序的many_initclassmethod,以提供实现所需行为的自定义ListSerializer,它as shown in DRF documentation。在

其次,最好重写create()或{}方法,而不是调用其中一个的save()。在

您的实现可能是这样的:

class CustomListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        more_business_logic()
        instances = [
            Widget(**attrs) for attrs in validated_data
        ]
        return Widget.objects.bulk_create(instances)

然后在BulkWidgetSerializer中:

^{pr2}$

一个问题:如果您在重写方法期间依赖于子类中的任何一个来支持批量部分更新(例如validate()),请不要忘记将正确的kwarg从父类传递给子类。在

您阅读了错误的文档部分,并且您的方法不正确。在

The default implementation for multiple object creation is to simply call .create() for each item in the list. If you want to customize this behavior, you'll need to customize the .create() method on ListSerializer class that is used when many=True is passed.

这确保了你想要发生的更多业务逻辑将发生在你传递到该列表中的每个项目上。在

根据文档-http://www.django-rest-framework.org/api-guide/serializers/#customizing-multiple-create

似乎您正在用many=True实例化序列化程序。在本例中,ListSerializer是在内部实例化的(您可以在类方法^{}中找到它的代码)。在

因此,ListSerializersave()方法被调用。如果必须重写save方法,请首先创建自定义列表序列化程序:

class CustomListSerializer(serializers.ListSerializer):
    def save(self):
         ...

然后通过指定list_serializer_class,将此自定义列表序列化程序添加到BulkWidgetSerializer

^{pr2}$

正如其他人指定的那样,最好重写create或{}方法,而不是save

相关问题 更多 >

    热门问题