Django动态生成的序列化器

dfuffjeb  于 2023-06-25  发布在  Go
关注(0)|答案(2)|浏览(147)

有没有一种方法可以动态生成Django REST框架序列化器?
考虑到:

class BlogSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = models.Blog
            fields = get_all_model_fields(models.Blog)
    
    class PostSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = models.Post
            fields = get_all_model_fields(models.Post)
     
    
    class UserSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = models.User
            fields = get_all_model_fields(models.User)

我想知道像下面这样的例子是否可能:

from django.apps import apps

models = [model for model in apps.get_models()]

for model in models:
    type(model.__name__+'Serializer',(serializers.ModelSerializer,),{
       type("Meta",(),{
           "model":model,
           "fields": get_all_model_fields(model)
       })
    })

或者有没有其他方法来生成DRF串行器?

byqmnocz

byqmnocz1#

下面是一个为给定的Model构建ModelSerializer的函数(使用Django 3.2,DRF 3.12.4和Python 3.8测试):

import types
from functools import lru_cache
from typing import Type

from django.db import models
from rest_framework import serializers

@lru_cache(maxsize=0)
def model_serializer(model: Type[models.Model]) -> Type[serializers.ModelSerializer]:
    meta_class = types.new_class("Meta")
    setattr(meta_class, "model", model)
    setattr(meta_class, "fields", "__all__")
    result = types.new_class(
        model.__name__ + "Serializer", (serializers.ModelSerializer,), {}
    )
    setattr(result, "Meta", meta_class)
    return result

如果您确定对每个序列化程序只调用此函数一次,则可以省略@lru_cache以保留一些内存。
示例用法:

class MyModel(models.Model):
    some = models.CharField(max_length=123)
    other = models.IntegerField()

MyModelSerializer = model_serializer(MyModel)
my_serializer = MyModelSerializer({"some": "abc", "other": 1234})
my_serializer.is_valid(True)

要将所有模型的序列化器添加到当前模块的命名空间:

from django.apps import apps

for model in apps.get_models():
    serializer_type = model_serializer(model)
    globals()[serializer_type.__name__] = serializer_type
p5fdfcr1

p5fdfcr12#

你的方法是可行的--但是对于Django来说,要找到这些序列化器,你必须将它们分配给模块名称空间。
在您的代码中,您只需调用type--序列化器类将被创建并立即“丢弃”。即使Django基类serializers.ModelSerializer在注册表中保留了对它的引用,您也无法导入序列化器并使用它们。
您所要做的就是将它们添加到globals()返回的字典中。同样,你为类创建的命名空间也必须是一个字典--因为你调用的是“type”,但实际上并没有将其名称分配为“ meta”,你创建的是一个集合,而不是一个字典,你对type的调用将失败,因为它需要一个字典。
所以,我没有检查代码是否真的可以工作,但是基于你的想法是:

from django.apps import apps

models = [model for model in apps.get_models()]

for model in models:
    name = f"{model.__name__}Serializer"
    globals()[name] =  type(name,(serializers.ModelSerializer,),{
       "Meta": type("Meta",(),{
           "model":model,
           "fields": get_all_model_fields(model)
       })
    })
del models, model, name

相关问题