All, I'm trying to implement a custom form field similar to the Tagging example.
Here's a simplified example of the model I'm using: class Port(meta.model): number = meta.IntegerField() protocol = meta.CharField(maxlength=4) class Application(meta.model): name = meta.CharField(maxlength=50) version = meta.IntegerField() ports = meta.ManyToManyField(Port) I'd like users to enter '80:tcp, 443:tcp' and have this validated and saved appropriately. With the AddManipulator everything is fine: My validation routine works, so does the render method and so does convert_post_data. A new application is therefore saved in the database (see below for the code I'm using). The problems start when ChangeManipulators are used. When the entry is read from the database the render method is now passed a list of ids rather than '80:tcp, 443:tcp' or similar which causes the lookups I do to fail. This makes me think that I'm missing something fundamental and am going about it in the wrong way. So, my questions are: 1. Am I going about this in the wrong way? 2. Should I be making a custom manipulator for the model rather than farming out the work to the field? 3. If not, then how do I make sure that 'render' gets passed consistent data. Thanks in advance for any pointers, F. P.S. For your viewing pleasure here's what I've been using so far: class FormPortField(formfields.TextField): requires_data_list = True def __init__(self, **kw): formfields.TextField.__init__(self, **kw) self.validator_list.append(self.isValidList) def isValidList(self, field_data, all_data): for datum in field_data: for port in datum.split(','): if port.lower().strip() != 'icmp': try: no, proto = port.split(':') except ValueError: raise validators.ValidationError, _("Ports should be specified in the form 'number:protocol'. E.g. '80:tcp'") if int(no) < 1 or int(no) > 65355: raise validators.ValidationError, _("Port number must be between 1 and 65355") if proto.lower().strip() not in ['tcp', 'udp']: raise validators.ValidationError, _("Protocol must be either 'TCP' or 'UDP'") def render(self, data): if data is None: data = '' if isinstance(data, unicode): data = data.encode(DEFAULT_CHARSET) data = ', '.join(data) return '<input type="text" id="%s" class="v%s%s" name="%s" size="%s" value="%s" />' % \ (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', self.field_name, 40, escape(data)) def convert_post_data(self, new_data): name = self.get_member_name() if new_data.has_key(self.field_name): d = new_data.getlist(self.field_name) portlist=[] for datum in d: for n in datum.split(','): n = n.strip() if n: if n.lower() == 'icmp': portlist.append(ports.get_object(protocol__exact="icmp").id) else: port, proto = n.split(':') port_ref = ports.get_object(number__exact=int(port), protocol__exact=proto.lower()) portlist.append(port_ref.id) new_data.setlist( name, portlist) class PortsField(meta.ManyToManyField): " Special case implementation of a Many to Many relationship to a 'Ports' table " def __init__(self, *args, **kw): meta.ManyToManyField.__init__(self, *args, **kw) self.help_text = kw.get('help_text', '') def get_manipulator_field_objs(self): if self.rel.raw_id_admin: return [formfields.CommaSeparatedIntegerField] else: return [curry(FormPortField)] --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-users -~----------~----~----~----~------~----~------~--~---