根据CharField选择动态生成Django表单

时间:2018-11-01 20:55:25

标签: python django

我有一个用户配置文件模型,该模型存储了许多第三方API密钥的配置,我正在尝试确定如何最好地根据用户做出的选择动态生成表单。该应用程序仅支持一部分服务,因此我正在使用CharField(+ CHOICES)来缩小用户试图提交配置的范围。用户可以根据需要提交任意数量的重复项(例如3套Cloud Service 1键)

我有这个模型:

class ServiceIntegration(models.Model):
    profile = models.ForeignKey(
        Profile,
        on_delete=models.CASCADE
    )

    CS1 = 'CS1'
    CS2 = 'CS2'
    SERVICE_CHOICES = (
        (CS1, 'Cloud Service 1'),
        (CS2, 'Cloud Service 2'),
    )
    alias = models.CharField(max_length=255)
    service = models.CharField(
        max_length=255,
        choices=SERVICE_CHOICES,
        default=CS1
    )
    config = JSONField()

在表单中,用户具有一个下拉菜单,其QuerySet设置为此模型的对象。当用户进行选择时,我想联系端点并在预定位置转储一些表单HTML。大概,我可以为每个集成设置一个表单,只需有一个视图即可接受选择,查找表单,然后将其渲染回去(与将数据发布到该端点相同)。

根据用户的选择动态呈现表单(并接受数据)的最佳选择是什么?

1 个答案:

答案 0 :(得分:0)

我最终编写了每个集成实现都继承自的BaseService类,以及每个实现返回的形式,如:

from service_integrations.forms import CloudServiceOneForm

class BaseService(ABC):

    def __init__(self, configuration):
        self.configuration = configuration
        super().__init__()

    @abstractmethod
    def get_form(self):
        pass

    @abstractmethod
    def get_service_name(self):
        pass

    @abstractmethod
    def check(self):
        pass

    @abstractmethod
    def run(self):
        pass


class CloudServiceOne(BaseService):

    def get_service_name(self):
        return 'Cloud Service One' # This should match the CharField Choice

    def get_form(self):
        return CloudServiceOneForm()

    def check(self):
        # Requirements for config go here
        if self.configuration.get('secret_key') and self.configuration.get('access_key'):
            return True
        else:
            return False

    def run(self):
        pass

以及可以从视图中调用以将相关表单传递到上下文的实用程序:

from service_integrations.classes import BaseService

def get_service(service):
    # Passes empty configurations to each subclass of BaseService and returns the handler based on the name.
    for cls in BaseService.__subclasses__():
        if cls({}).get_service_name() == service:
            return cls
    return None

然后您可以将表单传递到上下文中,例如:

service = get_service('Cloud Service One')
context = {
    'form': service.get_form()
}
return render(request, 'some_template.html', context)