Code

Changes between Version 5 and Version 6 of CustomFormFields


Ignore:
Timestamp:
03/15/06 07:07:55 (8 years ago)
Author:
Lllama
Comment:

Update explaining why custom manipulators are a better option

Legend:

Unmodified
Added
Removed
Modified
  • CustomFormFields

    v5 v6  
    88 
    99{{{ 
    10  
     10#!python 
    1111class Port(meta.model): 
    1212    number = meta.IntegerField() 
     
    4747 
    4848{{{ 
     49#!python 
    4950class FormPortField(formfields.TextField): 
    5051 
     
    117118 
    118119Wow.  What a mess.  We end up validating the data three times over.  What a pain.  But it works. 
     120 
     121=== Update 15.03.2006 === 
     122 
     123After 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 
     127class 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 
     166Here'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 
     168Why is this better?  Validation is only done where appropriate - in the 'isValidPortList' function and nowhere else. 
     169 
     170Are 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.