Added support to export to ODS
authorPA Parent <paparent@paparent.me>
Tue, 5 Jun 2012 20:36:48 +0000 (16:36 -0400)
committerPA Parent <paparent@paparent.me>
Tue, 5 Jun 2012 20:36:48 +0000 (16:36 -0400)
CHANGES
auf/__init__.pyc [deleted file]
auf/django/export/admin.py
auf/django/export/templates/admin/export/change_list.html
setup.py

diff --git a/CHANGES b/CHANGES
index 6ae1eac..f6497b4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -10,3 +10,8 @@ auf.django.export
 ---
 
 * Bug: Fix unicode error for values
+
+0.3
+---
+
+* New feature: Added Export to ODS
diff --git a/auf/__init__.pyc b/auf/__init__.pyc
deleted file mode 100644 (file)
index 2bfd785..0000000
Binary files a/auf/__init__.pyc and /dev/null differ
index de733ab..f3750dc 100644 (file)
@@ -1,10 +1,17 @@
 # -*- encoding: utf-8 -*-
 
 import csv
+from StringIO import StringIO
+
+from odf.opendocument import OpenDocumentSpreadsheet
+from odf.style import Style, TextProperties, TableColumnProperties
+from odf.text import P
+from odf.table import Table, TableRow, TableCell
+
 from django.core.urlresolvers import reverse
 from django.contrib import admin
 from django.utils.functional import update_wrapper
-from django.http import Http404, HttpResponse, HttpResponseBadRequest
+from django.http import HttpResponse
 
 # Create a notation similar to queryset filter
 SEPARATOR = u"__"
@@ -12,6 +19,17 @@ SEPARATOR = u"__"
 # String return if lookup property failed
 EMPTY = u""
 
+
+def txt(msg):
+    text = msg
+    if not isinstance(msg, unicode):
+        try:
+            text = unicode (msg, "utf-8")
+        except TypeError:
+            pass
+    return text
+
+
 class ExportAdmin(admin.ModelAdmin):
     change_list_template = 'admin/export/change_list.html'
 
@@ -22,7 +40,8 @@ class ExportAdmin(admin.ModelAdmin):
         if extra_context is None:
             extra_context = {}
         extra_context.update({
-            'export_url' : reverse("admin:%s_%s_export" % (self.model._meta.app_label, self.model._meta.module_name))
+            'export_csv_url' : reverse("admin:%s_%s_export_csv" % (self.model._meta.app_label, self.model._meta.module_name)),
+            'export_ods_url' : reverse("admin:%s_%s_export_ods" % (self.model._meta.app_label, self.model._meta.module_name)),
         })
         return super(ExportAdmin, self).changelist_view(request, extra_context)
 
@@ -30,20 +49,18 @@ class ExportAdmin(admin.ModelAdmin):
     def get_urls(self):
         from django.conf.urls.defaults import patterns, url
 
-        def wrap(view):
-            def wrapper(*args, **kwargs):
-                return self.admin_site.admin_view(view)(*args, **kwargs)
-            return update_wrapper(wrapper, view)
-
+        urls = super(ExportAdmin, self).get_urls()
         info = self.model._meta.app_label, self.model._meta.module_name
 
         urlpatterns = patterns('',
-            url(r'^export/$',
-                wrap(self.export),
-                name='%s_%s_export' % info),
+            url(r'^export-csv/$',
+                self.admin_site.admin_view(self.export_csv),
+                name='%s_%s_export_csv' % info),
+            url(r'^export-ods/$',
+                self.admin_site.admin_view(self.export_ods),
+                name='%s_%s_export_ods' % info),
         )
-        urlpatterns += super(ExportAdmin, self).get_urls()
-        return urlpatterns
+        return urlpatterns + urls
 
     def get_object_value(self, obj, header):
         """
@@ -67,22 +84,81 @@ class ExportAdmin(admin.ModelAdmin):
             except:
                 return EMPTY
 
-    def get_default_csv_fields(self):
+    def get_default_export_fields(self):
       fields_name = [f.name for f in  self.model._meta.fields]
       for fk in self.model._meta._related_objects_cache.keys():
           fields_name = fields_name + [u"%s%s%s" % (fk.var_name, SEPARATOR, f.name) for f in fk.model._meta.fields]
       return fields_name
 
-    def export(self, request):
+
+    def get_export_fields(self):
         """
-        Generate HTTP response as CSV file from  csv_fields property.
         This property is a list of string, which should have queryset filter notation style (with X2 underscore).
         If there is no fields, the models is full introspected, stop at 1 depth level.
         """
-        csv_fields = getattr(self, 'csv_fields', None)
 
-        if csv_fields is None:
-            csv_fields = self.get_default_csv_fields()
+        export_fields = getattr(self, 'export_fields', None)
+
+        if export_fields is None:
+            export_fields = getattr(self, 'csv_fields', None)
+
+        if export_fields is None:
+            export_fields = self.get_default_export_fields()
+
+        return export_fields
+
+    def export_ods(self, request):
+        """
+        Generate HTTP response as ODS file from export_fields property.
+        """
+        export_fields = self.get_export_fields()
+
+        qs = self.queryset(request)
+
+        response = HttpResponse(mimetype='application/vnd.oasis.opendocument.spreadsheet')
+        response['Content-Disposition'] = 'attachment; filename=%s.ods' % unicode(self.model._meta.verbose_name_plural)
+
+        doc = OpenDocumentSpreadsheet()
+        style = Style(name="Large number", family="table-cell")
+        style.addElement(TextProperties(fontfamily="Arial", fontsize="15pt"))
+        doc.styles.addElement(style)
+        widewidth = Style(name="co1", family="table-column")
+        widewidth.addElement(TableColumnProperties(columnwidth="2.8cm", breakbefore="auto"))
+        doc.automaticstyles.addElement(widewidth)
+
+        table = Table()
+        if len (export_fields) > 0:
+            tr = TableRow ()
+            table.addElement (tr)
+            for item in export_fields:
+                tc = TableCell ()
+                tr.addElement (tc)
+                p = P(stylename = style, text = txt(item))
+                tc.addElement (p)
+
+        for o in qs:
+            tr = TableRow ()
+            table.addElement (tr)
+
+            for attr in export_fields:
+                value = self.get_object_value(o, attr)
+                tc = TableCell ()
+                tr.addElement (tc)
+                p = P (stylename = style, text = txt(value))
+                tc.addElement (p)
+
+        doc.spreadsheet.addElement(table)
+        buffer = StringIO ()
+        doc.write(buffer)
+
+        response.write(buffer.getvalue())
+        return response
+
+    def export_csv(self, request):
+        """
+        Generate HTTP response as CSV file from export_fields property.
+        """
+        csv_fields = self.get_export_fields()
 
         qs = self.queryset(request)
 
@@ -104,4 +180,3 @@ class ExportAdmin(admin.ModelAdmin):
             writer.writerow(row)
 
         return response
-
index 02f9703..3b9983e 100644 (file)
@@ -5,7 +5,8 @@
 {% block object-tools %}
     <ul class="object-tools">
 
-        <li><a href="{{ export_url }}">{% trans 'Export CSV' %}</a></li>
+        <li><a href="{{ export_csv_url }}">{% trans 'Export CSV' %}</a></li>
+        <li><a href="{{ export_ods_url }}">{% trans 'Export ODS' %}</a></li>
                {% if has_add_permission %}
             <li><a href="{{add_url}}{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name|escape as name %}Add {{name}}{% endblocktrans %}</a></li>
         {% endif %}
index c8383cf..50253ca 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
 import sys, os
 
 name = 'auf.django.export'
-version = '0.2'
+version = '0.3'
 
 setup(name=name,
       version=version,