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
-~----------~----~----~----~------~----~------~--~---

Reply via email to