Django:呈现一种与模型截然不同的形式,并以Django-ish方式呈现多个字段值?

时间:2010-04-09 08:05:13

标签: python django

我正在为Django做一个防火墙管理应用程序,这是(简化)模型:

class Port(models.Model):
    number = models.PositiveIntegerField(primary_key=True)
    application = models.CharField(max_length=16, blank=True)

class Rule(models.Model):
    port = models.ForeignKey(Port)
    ip_source = models.IPAddressField()
    ip_mask = models.IntegerField(validators=[MaxValueValidator(32)])
    machine = models.ForeignKey("vmm.machine")

然而,我想要做的是向用户显示一个用于输入规则的表单,但其组织与模型完全不同:

端口80

O未打开

O Everywhere

O具体地址:

---------删除字段

---------删除字段

+添加地址字段

港口443

...等

其中Not open表示给定端口没有规则,Everywhere表示给定端口只有一个规则(0.0.0.0/0),specific addresses您可以根据需要添加任意数量的地址(我使用JQuery执行此操作),这将生成尽可能多的规则。

现在我做了一个完全“手工制作”的版本,这意味着我完全在我的模板中创建表单,使用前缀设置输入名称,并在我的视图中解析所有POST的内容(这非常痛苦,并且意味着有没有必要使用Web框架。)

我还有一个将规则聚合在一起的类,可以轻松地预填表单,其中包含“不开放,无处不在......”的信息。我将这些列表传递给模板,因此它充当我的模型和我的“手工”形式之间的接口:

class MachinePort(object):
    def __init__(self, machine, port):
        self.machine = machine
        self.port = port

    @property
    def fully_open(self):
        for rule in self.port.rule_set.filter(machine=self.machine):
            if ipaddr.IPv4Network("%s/%s" % (rule.ip_source, rule.ip_mask)) == ipaddr.IPv4Network("0.0.0.0/0"):
                return True
        else :
            return False

    @property
    def partly_open(self):
        return bool(self.port.rule_set.filter(machine=self.machine)) and not self.fully_open

    @property
    def not_open(self):
        return not self.partly_open and not self.fully_open

但这一切都相当难看!你是否有人知道是否有一种优雅的方式来做到这一点?特别是表单...我不知道如何有一个可以有一个未定义的字段数量的表单,也不知道如何将这些字段转换为Rule个对象(因为所有的规则字段都必须是从表单中收集),既没有如何保存多个对象......我可以尝试入侵Form类,但对于这样一个特殊情况似乎太过分了。我有什么不好的功能吗?

2 个答案:

答案 0 :(得分:1)

您可以通过继承Form并在构造函数中添加字段来创建常用的Forms对象,如:

self.base_fields[field_name] = field_instance

对于Rule,您可以根据自己的规则创建Field自定义的自定义validate(),并将其添加到您的自定义表单中。

是的,它必须是handmande(AFAIK),但它不是代码。

答案 1 :(得分:1)

好的,最后我通过使模型更接近我想要呈现给用户的模型来运行它。但与问题的主题相关:

1)嵌套的表单/表单集不是内置的Django功能,很难自己实现,实际上并不需要......相反,应该使用表单和表单集'前缀。

2)尝试使用不基于模型的表单,处理数据,然后将其重新注入模型中,代码要比修改模型稍微好一点,以获得更好的模型基于形式。 所以我做的是修改了这样的模型:

class PortConfig(Serializable):
    port = models.ForeignKey(Port, editable=False)
    machine = models.ForeignKey("vmm.machine", editable=False)
    is_open = models.CharField(max_length=16, default="not_open", choices=is_open_choices)

class Rule(Serializable):
    ip_source = models.CharField(max_length=24)
    port_config = models.ForeignKey(PortConfig)

然后我只使用了PortConfig的“模型表单集”和Rule的“模型内联表单集”,其中PortConfig作为外键,它完美无缺

3)我使用这个优秀的JS库http://code.google.com/p/django-dynamic-formset/来添加“添加字段”和“删除字段”链接......你几乎无所事事。

相关问题