Commits

Alexandre Beaulieu committed 3a951a2

Moved helpers to common project. Added simple unit test for csv2model. Implemented csv2model.

  • Participants
  • Parent commits 36b0fed

Comments (0)

Files changed (5)

File achievements/helpers.py

-# Helper functions for the achievements application
-
-def csv2model(data, model, format, auto_save=False):
-    """
-        Parses a CSV file, extracts and saves models according to a
-        specific format. the format is a dictionary in the following
-        form:
-        
-        format = { 'map': ['field1', 'field2', ...],
-                   'include': ['field2'], # None -> Include all
-                   'exclude': ['field1'], # None -> Don't exclude
-                   'delimiter': ','
-                 }
-                 
-         The keys 'include' and 'exclude' can be ommitted and will default
-         to None. The key 'delimiter' will default to ',' if ommitted.
-                 
-         @param data an iterable structure of strings representing one
-                     line in the CSV file.
-         @param model the model to map the CSV data to.
-         @param format the format dictionary as described above.
-         @param auto_save whether to automatically save the models to
-                          the database.
-         
-         @return A list of successfully converted models. If auto_save
-                 is enabled, then the database entries for the converted
-                 models have also been created.
-    """
-    # Defaults
-    DELIMITER = ','
-    INCLUDE = None
-    EXCLUDE = None
-    if 'delimiter' in format:
-        DELIMTIER = format['delimiter']
-    if 'include' in format:
-        INCLUDE = format['include']
-    if 'exclude' in format:
-        EXCLUDE = format['exclude']
-        
-    # TODO: Implementation stub
-    
-    return []

File achievements/tests.py

-"""
-This file demonstrates writing tests using the unittest module. These will pass
-when you run "manage.py test".
 
-Replace this with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-
-class SimpleTest(TestCase):
-    def test_basic_addition(self):
-        """
-        Tests that 1 + 1 always equals 2.
-        """
-        self.assertEqual(1 + 1, 2)

File achievements/views.py

 
 from achievements.models import Achievement, Award
 from achievements.forms import ImportForm
-from achievements import helpers
+from hard import utils
 
 def list(request, username=None):
     if username is not None:
     if request.method == 'POST':
         form = ImportForm(request.POST, request.FILES)
         if form.is_valid():
-            models = helpers.csv2model(request.FILES['file'], Achievement, {'map': ['title', 'desc']}, auto_save=True)
+            models = utils.csv2model(request.FILES['file'], Achievement, {'map': ['title', 'desc']}, auto_save=True)
             return redirect('import_success', count=len(models), achievements=models)
     else:
         form = ImportForm()

File hard/tests.py

 """
 
 from django.test import TestCase
+from achievements.models import Achievement
+from . import utils
 
 
-class SimpleTest(TestCase):
-    def test_basic_addition(self):
+class csv2model_test(TestCase):
+    
+    _data = "Tested, Wrote a Test Case\nPolyvalent, Wrote a fixture, Extra Field 1"
+
+    _format = {'map': ['title', 'desc']}
+    
+    def test_convert(self):
         """
-        Tests that 1 + 1 always equals 2.
+        Tests that CSV is parsed properly into models.
         """
-        self.assertEqual(1 + 1, 2)
+        models = utils.csv2model(self._data, Achievement, self._format)
+        
+        self.assertEquals(len(models), 2)

File hard/utils.py

+# Helper functions for the achievements application
+# from django.db.models import get_models, get_app
+import re
+
+def csv2model(data, model, format, auto_save=False):
+    """
+        Parses a CSV file, extracts and saves models according to a
+        specific format. the format is a dictionary in the following
+        form:
+        
+        format = { 'map': ['field1', 'field2', ...],
+                   'exclude': ['field1'], # [] -> Don't exclude
+                   'delimiter': ','
+                 }
+                 
+         The key 'exclude' can be ommitted and will default to None. 
+         The key 'delimiter' will default to ',' if ommitted.
+                 
+         @param data an iterable structure of strings representing one
+                     line in the CSV file.
+         @param model the model to map the CSV data to.
+         @param format the format dictionary as described above.
+         @param auto_save whether to automatically save the models to
+                          the database.
+         
+         @return A list of successfully converted models. If auto_save
+                 is enabled, then the database entries for the converted
+                 models have also been created.
+    """
+    
+    DELIMITER = ','
+    EXCLUDE = []
+    
+    if 'delimiter' in format:
+        DELIMTIER = format['delimiter']
+    if 'exclude' in format:
+        EXCLUDE = format['exclude']
+
+    model_fields = get_field_names(model)
+    models = []
+    
+    if 'map' not in format:
+        return models
+    MAP = format['map']
+    
+    for line in data.replace('\r', '').split('\n'): 
+        line_fields = line.split(DELIMITER)
+        
+        # Skip rows with insufficient fields
+        if len(line_fields) < len(MAP):
+            continue
+        
+        # Map the parsed fields to our field names
+        for (k, v) in zip(MAP, line_fields):
+            # Only set fields that exist in the model and aren't marked to be
+            # excluded.
+            if k in model_fields and k not in EXCLUDE:
+                model_fields[k] = v
+    
+        new_model = model(**model_fields)
+        models.append(new_model)
+        
+        if auto_save:
+            new_model.save()
+        
+        # Reset the field schema
+        for k in model_fields.iterkeys():
+            model_fields[k] = None
+            
+    return models
+
+def get_field_names(model):
+    """
+        Small wrapper to return the list of fields that are part of a model.
+        
+        @param model a model class for which to extract all field names.
+        @return a dictionary of field names for the given model.
+    """
+    return dict((field.name, None) for field in model._meta.fields)