Django 动态生成的序列化器
Django dynamically generated serializer
有没有办法动态生成 Django 休息框架序列化程序?
考虑到这一点:
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 序列化程序吗?
您的方法会奏效 - 但要让 Django 找到这些序列化程序,您必须将它们分配给模块命名空间。
在您的代码中,您只需调用 type
- 序列化程序 class 会立即创建并“丢弃”。即使基础 Django class serializers.ModelSerializer
在注册表中保留对它的引用,您也无法导入序列化程序并使用它们。
您所要做的就是将它们添加到 globals()
返回的字典中。同样,您为 class 创建的名称空间也必须是一个字典 - 因为您正在调用“type”但实际上没有将其名称分配为“Meta”,所以您创建了一个集合,而不是字典,并且您的调用键入将失败,因为它需要字典。
所以,我没有检查代码是否真的有效,但基于你的想法是:
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
这是一个为给定 Model
构建 ModelSerializer
的函数(使用 Django 3.2、DRF 3.12.4 和 Python 3.8 测试):
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
有没有办法动态生成 Django 休息框架序列化程序?
考虑到这一点:
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 序列化程序吗?
您的方法会奏效 - 但要让 Django 找到这些序列化程序,您必须将它们分配给模块命名空间。
在您的代码中,您只需调用 type
- 序列化程序 class 会立即创建并“丢弃”。即使基础 Django class serializers.ModelSerializer
在注册表中保留对它的引用,您也无法导入序列化程序并使用它们。
您所要做的就是将它们添加到 globals()
返回的字典中。同样,您为 class 创建的名称空间也必须是一个字典 - 因为您正在调用“type”但实际上没有将其名称分配为“Meta”,所以您创建了一个集合,而不是字典,并且您的调用键入将失败,因为它需要字典。
所以,我没有检查代码是否真的有效,但基于你的想法是:
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
这是一个为给定 Model
构建 ModelSerializer
的函数(使用 Django 3.2、DRF 3.12.4 和 Python 3.8 测试):
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