| 120 | |
| 121 | === Update 15.03.2006 === |
| 122 | |
| 123 | After much searching and fiddling and wondering I've decided that I went about this all wrong. Custom form fields are not the answer to my problem, manipulators are. This is the code I'm now using: |
| 124 | |
| 125 | {{{ |
| 126 | #!python |
| 127 | class ApplicationAddManipulator(applications.AddManipulator): |
| 128 | |
| 129 | def __init__(self): |
| 130 | applications.AddManipulator.__init__(self) |
| 131 | newfields = [] |
| 132 | for field in self.fields: |
| 133 | if field.field_name == 'ports': |
| 134 | field = formfields.TextField(field_name='ports', length=30, maxlength=200, validator_list=[self.isValidPortList]) |
| 135 | newfields.append(field) |
| 136 | self.fields = newfields |
| 137 | |
| 138 | def isValidPortList(self, field_data, all_data): |
| 139 | for port in field_data.split(','): |
| 140 | if port.lower().strip() != 'icmp': |
| 141 | try: |
| 142 | no, proto = port.split(':') |
| 143 | except ValueError: |
| 144 | raise validators.ValidationError, _("Ports should be specified in the form 'number:protocol'. E.g. '80:tcp'") |
| 145 | try: |
| 146 | if int(no) < 1 or int(no) > 65355: |
| 147 | raise validators.ValidationError, _("Port number must be between 1 and 65355") |
| 148 | except ValueError: |
| 149 | raise validators.ValidationError, _("Port number must be between 1 and 65355") |
| 150 | if proto.lower().strip() not in ['tcp', 'udp']: |
| 151 | raise validators.ValidationError, _("Protocol must be either 'TCP' or 'UDP'") |
| 152 | |
| 153 | def save(self, new_data): |
| 154 | portIds = [] |
| 155 | if new_data['ports'] and new_data['ports'].strip().lower(): |
| 156 | for port in new_data['ports'].split(','): |
| 157 | if port.strip().lower() == 'icmp': |
| 158 | portIds.append(ports.get_object(protocol__exact='icmp').id) |
| 159 | else: |
| 160 | no, proto = port.strip().lower().split(':') |
| 161 | portIds.append(ports.get_object(protocol__exact=proto, number__exact=int(no)).id) |
| 162 | new_data['ports'] = portIds |
| 163 | return applications.AddManipulator.save(self, new_data) |
| 164 | }}} |
| 165 | |
| 166 | Here's what the code actually does. The new custom manipulator subclasses the standard AddManipulator for the Application model. When a new instance is created (i.e. the __init__ method is called) then the AddManipulator's fields are copied and the 'ports' multiple-select box replaced with a standard text field. The field has a custom validator attached to it and the save method is overridden to convert the user's input into a valid list of ports. |
| 167 | |
| 168 | Why is this better? Validation is only done where appropriate - in the 'isValidPortList' function and nowhere else. |
| 169 | |
| 170 | Are there still issues? Yep. I still don't like the calling of 'do_html2python' when data could be invalid. This really doesn't appear to make sense to me. A lot of the manipulator code will change when Magic Removal hits trunk. To what extent this will correct my concerns remains to be seen. |