首页 > 解决方案 > 如何在没有构造函数的情况下在 Python 中动态添加自定义类变量

问题描述

如何在不调用构造函数的情况下将类变量动态添加到 Python 类中?在自定义 Django 石墨烯中继节点过滤器中添加自定义查询字段时,这是必需的。

在下面的示例代码中,is_controller类变量是静态定义的。如何在不使用类外的构造函数或代码的情况下动态生成 BooleanFilter 的变量名称和参数?

这是运行 GraphQL 查询所必需的,例如allSiteEntities(is_controller: true) { ... }

class SiteEntityFilter(FilterSet):
    """Filter for SiteEntityNode that includes component filters"""

    is_controller = BooleanFilter(
        field_name=controller_component, lookup_expr="isnull", exclude=True
    )

    class Meta:
        model = SiteEntity
        fields = {
            "site": ["exact"],
            "name": ["exact", "icontains", "istartswith"],
            "modified_at": ["exact", "gt", "lt"],
        }


class SiteEntityNode(DjangoObjectType):
    class Meta:
        model = SiteEntity
        filterset_class = SiteEntityFilter
        fields = [
            "id",
            "site",
            "name",
            "controller_component",
            "created_at",
            "modified_at",
        ]
        interfaces = (relay.Node,)

标签: pythondjangographene-django

解决方案


通过将动态数据添加到设置中,可以将过滤器和字段动态添加到 GraphQL 查询中。问题是没有调用构造函数,这就是为什么__init__()不能使用函数并且setattr()在类定义之后也不起作用的原因。但是,在使用locals()时可以添加也被 Graphene Relay 接口代码拾取的类变量。

自定义过滤器对于检查是否存在具有用户友好名称的反向 ForeignKey 很有用。

# my_project/settings.py
SITE_ENTITY_COMPONENTS = [
    "controller_component",
    "peripheral_component", 
    "hydroponic_system_component",
    "water_cycle_component",
]


# my_app/graphql.py
class SiteEntityFilter(FilterSet):
    """Filter for SiteEntityNode that includes component filters"""

    for component in settings.SITE_ENTITY_COMPONENTS:
        # controller_component --> is_controller
        attribute_name = f"is_{component.split('_component')[0]}"
        locals()[attribute_name] = BooleanFilter(
            field_name=component, lookup_expr="isnull", exclude=True
        )

    class Meta:
        model = SiteEntity
        fields = {
            "site": ["exact"],
            "name": ["exact", "icontains", "istartswith"],
            "modified_at": ["exact", "gt", "lt"],
        }

class SiteEntityNode(DjangoObjectType):
    class Meta:
        model = SiteEntity
        filterset_class = SiteEntityFilter
        fields = [
            "id",
            "site",
            "name",
            "created_at",
            "modified_at",
        ].extend(settings.SITE_ENTITY_COMPONENTS)
        interfaces = (relay.Node,)

推荐阅读