发布
社区首页 >问答首页 >Django动态生成序列化程序

Django动态生成序列化程序
EN

Stack Overflow用户
提问于 2020-11-12 19:11:12
回答 2查看 946关注 0票数 1

有办法动态生成Django rest框架序列化器吗?

考虑到这一点:

代码语言:javascript
代码运行次数:0
复制
    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)

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

代码语言:javascript
代码运行次数:0
复制
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串行化器?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-04-25 06:11:13

下面是为给定的ModelSerializer构建Model的函数(用Django 3.2、DRF 3.12.4和Python3.8进行测试):

代码语言:javascript
代码运行次数:0
复制
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

如果您确信只对每个序列化程序调用该函数一次,则可以省略缓存以保留一些内存。

示例用法:

代码语言:javascript
代码运行次数:0
复制
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)

若要将所有模型的序列化器添加到当前模块的命名空间,请执行以下操作:

代码语言:javascript
代码运行次数:0
复制
from django.apps import apps

for model in apps.get_models():
    serializer_type = model_serializer(model)
    globals()[serializer_type.__name__] = serializer_type
票数 2
EN

Stack Overflow用户

发布于 2020-11-12 21:05:22

您的方法是可行的,但是Django要想找到这些序列化器,就必须将它们分配给模块命名空间。

在您的代码中,只需调用type --将立即创建序列化程序类并“丢弃”。即使基本Django类serializers.ModelSerializer在注册表中保留了对它的引用,您也无法导入序列化程序并使用它们。

您所要做的就是将它们添加到globals()返回的字典中。类似地,您为该类创建的命名空间还必须是一个字典( -since ),您正在调用" type“,但实际上没有将它的名称指定为"Meta",而是创建了一个集合,而不是一个字典,您对类型的调用将失败,因为它期待一个字典。

因此,我没有检查代码是否实际工作,但基于您的想法是:

代码语言:javascript
代码运行次数:0
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64810287

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档