Index: main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py	(revision 8213)
+++ main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py	(revision 8214)
@@ -37,5 +37,6 @@
 _ = MessageFactory = zope.i18nmessageid.MessageFactory('waeup.kofa')
 
-DELETIONMARKER = 'XXX'
+DELETION_MARKER = 'XXX'
+IGNORE_MARKER = '<IGNORE>'
 
 CREATED = 'created'
@@ -825,5 +826,5 @@
 
 class IFieldConverter(Interface):
-    def update_request_data(self, name, value, schema_field, prefix=''):
+    def request_data(name, value, schema_field, prefix='', mode='create'):
         """Create a dict with key-value mapping as created by a request.
 
@@ -831,4 +832,6 @@
         similar input and represent an attribute to be set to a
         representation of value.
+
+        `mode` gives the mode of import.
 
         :meth:`update_request_data` is then requested to turn this
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py	(revision 8213)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py	(revision 8214)
@@ -34,5 +34,5 @@
 from waeup.kofa.interfaces import (
     IBatchProcessor, FatalCSVError, IObjectConverter, IUserAccount,
-    IObjectHistory, VALIDATED, DELETIONMARKER)
+    IObjectHistory, VALIDATED, DELETION_MARKER, IGNORE_MARKER)
 from waeup.kofa.interfaces import MessageFactory as _
 from waeup.kofa.students.interfaces import (
@@ -169,12 +169,15 @@
             elif hasattr(obj, key):
                 # Set attribute to None if value is marked for deletion
-                if value == DELETIONMARKER:
-                    setattr(obj, key, None)
-                elif value is not None:
+                #if value == DELETION_MARKER:
+                #    setattr(obj, key, None)
+                #elif value is not None:
+                #    setattr(obj, key, value)
+                #else:
+                #    # No change, no change log
+                #    continue
+                if value != '<IGNORE>':
                     setattr(obj, key, value)
-                else:
-                    # No change, no change log
-                    continue
-            items_changed += '%s=%s, ' % (key,value)
+                
+                    items_changed += '%s=%s, ' % (key,value)
         parent = self.getParent(row, site)
         if hasattr(obj,'student_id'):
@@ -215,5 +218,5 @@
         converter = IObjectConverter(iface)
         errs, inv_errs, conv_dict =  converter.fromStringDict(
-            row, self.factory_name)
+            row, self.factory_name, mode=mode)
         if row.has_key('reg_state') and \
             not row['reg_state'] in IMPORTABLE_STATES:
@@ -304,11 +307,15 @@
             if hasattr(obj, key):
                 # Set attribute to None if value is marked for deletion
-                if value == DELETIONMARKER:
-                    setattr(obj, key, None)
-                elif value is not None:
-                    setattr(obj, key, value)
-                    if key == 'certificate':
-                        value = value.code
-            items_changed += '%s=%s, ' % (key,value)
+                setattr(obj, key, value)
+                if key == 'certificate':
+                    value = value.code
+
+                #if value == DELETIONMARKER:
+                #    setattr(obj, key, None)
+                #elif value is not None:
+                #    setattr(obj, key, value)
+                #    if key == 'certificate':
+                #        value = value.code
+                items_changed += '%s=%s, ' % (key,value)
         parent = self.getParent(row, site)
         parent.__parent__.logger.info(
@@ -698,10 +705,11 @@
             if hasattr(obj, key) and not key in [
                 'current_session','current_level']:
+                setattr(obj, key, value)
                 # Set attribute to None if value is marked for deletion
-                if value == DELETIONMARKER:
-                    setattr(obj, key, None)
-                elif value is not None:
-                    setattr(obj, key, value)
-            items_changed += '%s=%s, ' % (key,value)
+                #if value == DELETIONMARKER:
+                #    setattr(obj, key, None)
+                #elif value is not None:
+                #    setattr(obj, key, value)
+                items_changed += '%s=%s, ' % (key,value)
         parent = self.getParent(row, site)
         parent.__parent__.logger.info(
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_student_data_update2.csv
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_student_data_update2.csv	(revision 8213)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_student_data_update2.csv	(revision 8214)
@@ -1,4 +1,4 @@
 date_of_birth,matric_number,phone
-1970-01-02,100000,
+1970-01-02,100000,<IGNORE>
 1970-01-03,100001,XXX
-1970-01-04,100002,
+1970-01-04,100002,<IGNORE>
Index: main/waeup.kofa/trunk/src/waeup/kofa/utils/batching.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/utils/batching.py	(revision 8213)
+++ main/waeup.kofa/trunk/src/waeup/kofa/utils/batching.py	(revision 8214)
@@ -32,5 +32,5 @@
 from waeup.kofa.interfaces import (
     IBatchProcessor, FatalCSVError, IObjectConverter,
-    ICSVExporter, DELETIONMARKER)
+    ICSVExporter, DELETION_MARKER, IGNORE_MARKER)
 
 class BatchProcessor(grok.GlobalUtility):
@@ -205,8 +205,10 @@
             if hasattr(obj, key):
                 # Set attribute to None if value is marked for deletion
-                if value == DELETIONMARKER:
-                    setattr(obj, key, None)
-                elif value is not None:
+                if value != '<IGNORE>':
                     setattr(obj, key, value)
+                #if value == DELETIONMARKER:
+                #    setattr(obj, key, None)
+                #elif value is not None:
+                #    setattr(obj, key, value)
         return
 
Index: main/waeup.kofa/trunk/src/waeup/kofa/utils/converters.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/utils/converters.py	(revision 8213)
+++ main/waeup.kofa/trunk/src/waeup/kofa/utils/converters.py	(revision 8214)
@@ -30,5 +30,5 @@
 from waeup.kofa.interfaces import (
     IObjectConverter, IResultEntryField, IFieldConverter, SubjectSource,
-    GradeSource)
+    GradeSource, DELETION_MARKER, IGNORE_MARKER)
 from waeup.kofa.schema.interfaces import IPhoneNumber
 from waeup.kofa.schoolgrades import ResultEntry
@@ -114,14 +114,16 @@
 class DefaultFieldConverter(grok.Adapter):
     grok.context(Interface)
-    grok.provides(IFieldConverter)
-
-    def request_data(self, name, value, schema_field, prefix=''):
+    grok.implements(IFieldConverter)
+
+    def request_data(self, name, value, schema_field, prefix='',
+                     mode='create'):
         return {prefix: value}
 
 class ListFieldConverter(grok.Adapter):
     grok.context(IList)
-    grok.provides(IFieldConverter)
-
-    def request_data(self, name, value, schema_field, prefix=''):
+    grok.implements(IFieldConverter)
+
+    def request_data(self, name, value, schema_field, prefix='',
+                     mode='create'):
         value_type = schema_field.value_type
         try:
@@ -144,7 +146,8 @@
     """
     grok.context(IPhoneNumber)
-    grok.provides(IFieldConverter)
-
-    def request_data(self, name, value, schema_field, prefix=''):
+    grok.implements(IFieldConverter)
+
+    def request_data(self, name, value, schema_field, prefix='',
+                     mode='create'):
         parts = value.split('-', 2)
         country = ''
@@ -168,7 +171,8 @@
 class ResultEntryConverter(grok.Adapter):
     grok.context(IResultEntryField)
-    grok.provides(IFieldConverter)
-
-    def request_data(self, name, value, schema_field, prefix=''):
+    grok.implements(IFieldConverter)
+
+    def request_data(self, name, value, schema_field, prefix='',
+                     mode='create'):
         """Turn CSV values into ResultEntry-compatible form data.
 
@@ -208,5 +212,5 @@
 
     grok.context(Interface)
-    grok.provides(IObjectConverter)
+    grok.implements(IObjectConverter)
 
     def __init__(self, iface):
@@ -217,5 +221,6 @@
         return
 
-    def fromStringDict(self, data_dict, context, form_fields=None):
+    def fromStringDict(self, data_dict, context, form_fields=None,
+                       mode='create'):
         """Convert values in `data_dict`.
 
@@ -262,4 +267,5 @@
 
         request = TestRequest(form={})
+        new_data = dict()
         for key, val in data_dict.items():
             field = form_fields.get(key, None)
@@ -269,4 +275,13 @@
                 schema_field = field.interface[field.__name__]
                 field_converter = IFieldConverter(schema_field)
+                if mode == 'update':
+                    if val == DELETION_MARKER:
+                        val = schema_field.missing_value
+                        if schema_field.required:
+                            val = schema_field.default
+                        new_data[key] = val
+                        continue
+                    if val == IGNORE_MARKER:
+                        continue
                 request.form.update(
                     field_converter.request_data(
@@ -283,5 +298,5 @@
             form_fields, 'form', obj, request)
 
-        new_data = dict()
+        #new_data = dict()
         errors = getWidgetsData(widgets, 'form', new_data)
 
