我用Django和DRF编写了以下代码:

class ServiceModelMetaClass(serializers.SerializerMetaclass, type):
    SERVICE_MODELS = {
        "email": EmailSubscriber,
        "push": PushSubscriber
    }

    def __call__(cls, *args, **kwargs):
        service = kwargs.get("data", {}).get("service")
        cls.Meta.subscriber_model = cls.SERVICE_MODELS.get(service)
        return super().__call__(*args, **kwargs)


class InterListsActionsSerializer(serializers.Serializer, metaclass=ServiceModelMetaClass):
    source_list_id = serializers.IntegerField()
    target_list_id = serializers.IntegerField()
    subscriber_ids = serializers.IntegerField(many=True, required=False)
    account_id = serializers.CharField()
    service = serializers.ChoiceField(choices=("email", "push"))

    class Meta:
        subscriber_model: Model = None

    def move(self):
        model = self.Meta.subscriber_model
        # Rest of the method code.

The purpose of this code is that this serializer might need doing operation on different models based on the service that the user wants to use. So I wrote this metaclass to prevent writing duplicate code and simply change the subscriber_model based on user's needs.
Now as you might know, serializers.Serializer uses a metaclass by its own, serializers.SerializerMetaclass. If I don't use this metaclass for creating my metaclass, it results in the following error:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases.
But when I try making my ServiceModelMetaClass metaclass to inherit from serializers.SerializerMetaclass it gives me this error:

   File "/project-root/segment_management/serializers/subscriber_list.py", line 33, in <module>
    class InterListsActionsSerializer(serializers.Serializer, metaclass=ServiceModelMetaClass):
  File "/project-root/segment_management/serializers/subscriber_list.py", line 36, in InterListsActionsSerializer
    subscriber_ids = serializers.IntegerField(many=True, required=False)
  File "/project-root/.venv/lib/python3.10/site-packages/rest_framework/fields.py", line 894, in __init__
    super().__init__(**kwargs)
TypeError: Field.__init__() got an unexpected keyword argument 'many'

我应该做什么来解决这个问题,或者是一个更好的替代方法,在不使用元类的情况下保持代码清洁?先谢谢你.

推荐答案

问题不在于元类,或者至少不是主要问题.第many=True章是你的IntegerField我查了一下,显然一个领域不能有many=True,只有一个Serializer可以.事实上,如果我们判断source code, we see [GitHub]:

def __new__(cls, *args, **kwargs):
    # We override this method in order to automatically create
    # `ListSerializer` classes instead when `many=True` is set.
    if kwargs.pop('many', False):
        return cls.many_init(*args, **kwargs)
    return super().__new__(cls, *args, **kwargs)

并且.many_init(…)实质上将该字段创建为子字段,并且wraps it in a ListSerializer [GitHub]:

@classmethod def many_init(cls, *args, **kwargs):
    # …
    child_serializer = cls(*args, **kwargs)
    list_kwargs = {
        'child': child_serializer,
    }
    # …
    meta = getattr(cls, 'Meta', None)
    list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
    return list_serializer_class(*args, **list_kwargs)

但我们基本上可以对字段应用相同的技巧,只需使用ListField [drf-doc]:

class InterListsActionsSerializer(
    serializers.Serializer, metaclass=ServiceModelMetaClass
):
    source_list_id = serializers.IntegerField()
    target_list_id = serializers.IntegerField()
    subscriber_ids = serializers.ListField(
        child=serializers.IntegerField(), required=False
    )
    account_id = serializers.CharField()
    service = serializers.ChoiceField(choices=('email', 'push'))

    class Meta:
        subscriber_model: Model = None

    def move(self):
        model = self.Meta.subscriber_model

Python相关问答推荐

如何使用Python中的clinicalTrials.gov API获取完整结果?

有条件地采样我的大型DF的最有效方法

Pystata:从Python并行运行stata实例

难以在Manim中正确定位对象

修复mypy错误-赋值中的类型不兼容(表达式具有类型xxx,变量具有类型yyy)

Python虚拟环境的轻量级使用

Pandas—在数据透视表中占总数的百分比

Polars asof在下一个可用日期加入

如果初始groupby找不到满足掩码条件的第一行,我如何更改groupby列,以找到它?

如何检测鼠标/键盘的空闲时间,而不是其他输入设备?

Python—压缩叶 map html作为邮箱附件并通过sendgrid发送

基于多个数组的多个条件将值添加到numpy数组

使用字典或列表的值组合

如何删除重复的文字翻拍?

在用于Python的Bokeh包中设置按钮的样式

递归函数修饰器

Polars表达式无法访问中间列创建表达式

在matplotlib中重叠极 map 以创建径向龙卷风图

按条件计算将记录拆分成两条记录

我如何处理超类和子类的情况