Django: представление формы, сильно отличающейся от модели, и с несколькими значениями полей способом Django-ish? - PullRequest
1 голос
/ 09 апреля 2010

В настоящее время я делаю приложение для управления брандмауэром для 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 Везде

O Конкретные адреса:

--------- удалить поле

--------- удалить поле

+ добавить поле адреса

Порт 443

... и т. Д.

Где Not open означает, что для данного порта нет никаких правил, Everywhere означает, что для данного порта существует только ОДНО правило (0.0.0.0/0), а с помощью specific addresses вы можете добавить как столько адресов, сколько вы хотите (я сделал это с помощью JQuery), что позволит создать столько правил.

Теперь я сделал версию полностью «ручной», что означает, что я создаю формы полностью в своих шаблонах, задаю имена входов с префиксом и анализирую все POST-элементы в моем представлении (что довольно болезненно и означает, что нет смысла использовать веб-фреймворк).

У меня также есть класс, который объединяет правила вместе, чтобы легко предварительно заполнить формы информацией "не открыто, везде ...". Я передаю их список шаблону, поэтому он действует как интерфейс между моей моделью и моей формой "ручной работы":

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 ]

1 голос
/ 29 апреля 2010

Хорошо, наконец-то я запустил его, приблизив модели к тому, что я хотел представить пользователю. Но связанные с темой вопроса:

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/, чтобы поместить ссылки «добавить поле» и «удалить поле» ... вам почти нечего делать.

1 голос
/ 09 апреля 2010

Вы можете создавать обычные объекты Forms, создав подклассы Form и добавив поля в конструктор, например:

self.base_fields[field_name] = field_instance

Что касается Rule, вы можете создать пользовательский Field, который будет validate() сам в соответствии с вашими правилами, и добавить его в свою пользовательскую форму, как указано выше.

Так что да, это должно быть handmande (AFAIK), но это не так много кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...