Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

treat None values as empty string (instead of 'None') #1

Closed
wants to merge 2 commits into from

3 participants

@tomster

in our application the backend (sqlalchemy) returns None values, which by default are rendered as 'None' strings in the form. We had to manually convert them to empty strings when (de-) serializing. instead of either a) creating our own String type or b) manually converting them in all our views, we tried adding this treatment directly to colander.

the question is: does serializing the None value to the string 'None' ever make sense in the context colander is used? (it makes perfect sense for pythons unicode(None) to return 'None', of course).

what do you think? does the change we made make sense?

@mcdonc
Owner

It's a good question. I'm wondering though, aside from your immediate problem of wanting None to represent the empty string during sqalchemy serialization, why would colander.String be a special case here? Should None represent the integer 0 if the node is the colander.Int type? The "today" datetime if None is passed to the serialize method of a colander.DateTime? It's currently pretty easy to explain that "colander.null represents the null value for any type and the null value is serialized by the widget as it sees fit", it's harder to start to make documentation exceptions for specific types.

@tomster

well, the intention is to better capture the None value ''semantically''. IOW if None is to mean 'nothing' semantically, how to best represent that in a form? the empty string seems suited best for this. so the None representation of an Integer would also be the empty string IMO. so i don't see the need to make special cases.

in any case, rendering the None value as a 'None' string really never would make sense in this context.

@dnouri
Collaborator

This is bugging me in my project too. I agree with Tom that rendering "None" as '' in a string widget is probably the most practical thing.

Not sure, but maybe "None" should be represented by the node's "missing" or "default"? (I have yet to figure out what the difference between the two is...)

@mcdonc
Owner

I think I agree. I just need to decide how to deal with None in the non-String widgets too to make this change make sense in a larger context.

missing= the deserialization default
default= the serialization default

@tomster

i think an empty string is appropriate for all text-input based widgets, regardless of their schema (i.e. integer, custom price, date etc.) it's just a representation of nothing.

@mcdonc
Owner

One thing that might make sense here is to do this in things like String, Date, Datetime, and any other scalar value where "falseness" means null, rather than the current:

def serialize(self, node, appstruct):
    if appstruct is colander.null:
        return colander.null
    ...

We could instead interpret nullness more widely:

def serialize(self, node, appstruct):
    if not appstruct:
        return colander.null
    ...

This would mean that if you defined a schema, you could give it a default serialization value, which would get returned when the type returned null from serialize:

name = colander.SchemaNode(String(), default='')

This would be the lowest-impact change possible, I think, and it's probably right regardless of whether we decide later to return non-null values from the default types during serialization of a logically null value.

@dnouri
Collaborator

Can't say I understand the implications but it sure sounds like a good way to do it.

@dnouri
Collaborator

I just had to change DateTime.serialize to look like your second example to be able to move forward with my deform datetime widget that wants to support empty values.

This is how I define my schema node:

end = colander.SchemaNode(colander.DateTime(), missing=None)

Does this look right?

+1 for the change.

@tomster
@dnouri
Collaborator

Fixed with #45.

@dnouri dnouri closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 25, 2011
  1. @tomster
  2. @tomster

    typo

    tomster authored
This page is out of date. Refresh to see the latest.
Showing with 18 additions and 1 deletion.
  1. +5 −1 colander/__init__.py
  2. +13 −0 colander/tests.py
View
6 colander/__init__.py
@@ -760,6 +760,8 @@ def __init__(self, encoding=None):
def serialize(self, node, appstruct):
if appstruct is null:
return null
+ elif appstruct is None:
+ return u''
try:
if isinstance(appstruct, unicode):
@@ -782,7 +784,9 @@ def serialize(self, node, appstruct):
def deserialize(self, node, cstruct):
try:
result = cstruct
- if not isinstance(result, unicode):
+ if result is None:
+ return u''
+ elif not isinstance(result, unicode):
if self.encoding:
result = unicode(str(cstruct), self.encoding)
else:
View
13 colander/tests.py
@@ -716,6 +716,12 @@ def test_deserialize_emptystring(self):
result = typ.deserialize(node, '')
self.assertEqual(result, '')
+ def test_deserialize_None_to_empty_string(self):
+ node = DummySchemaNode(None)
+ typ = self._makeOne(None)
+ result = typ.deserialize(node, None)
+ self.assertEqual(result, '')
+
def test_deserialize_uncooperative(self):
val = Uncooperative()
node = DummySchemaNode(None)
@@ -781,6 +787,13 @@ def test_serialize_unicode_to_None(self):
result = typ.serialize(node, value)
self.assertEqual(result, value)
+ def test_serialize_None_to_empty_string(self):
+ value = None
+ node = DummySchemaNode(None)
+ typ = self._makeOne()
+ result = typ.serialize(node, value)
+ self.assertEqual(result, u'')
+
def test_serialize_to_utf8(self):
uni = u'\xf8'
utf8 = uni.encode('utf-8')
Something went wrong with that request. Please try again.