Login

CSV Exporting of Model Data

Author:
monokrome
Posted:
November 11, 2009
Language:
Python
Version:
1.1
Score:
1 (after 1 ratings)

This is a basic view for exporting data from models. It is designed so that you can provide the GET variables used for searching/filtering within listdisplay pages in the admin, and the code will filter the same way.

It allows ouputting of model data in various formats using serializers.

This should be used as a urlpattern through get_url, so that you can use the admin_view decorator to properly secure the data.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.views.main import ChangeList
from django.http import HttpResponse, HttpResponseForbidden, Http404
from django.core.serializers import serialize
from django.template import loader, RequestContext
from django.template.defaultfilters import slugify
from django.db.models.loading import get_model
from django.utils.encoding import smart_str
import csv

ALLOWED_EXPORT_TYPES = {
    'csv': {
        'mimetype': 'text/csv',
        'filename': '%s.csv',
        'template': 'admin/export/csv',
    },
    'json': {
        'mimetype': 'text/json',
        'filename': '%s.json',
        'serializer': 'json',
    },
    'xml': {
        'mimetype': 'text/xml',
        'filename': '%s.xml',
        'serializer': 'xml',
    },
    'yaml': {
        'mimetype': 'text/yaml',
        'filename': '%s.yaml',
        'serializer': 'yaml',
    },
    'py': {
        'mimetype': 'application/python',
        'filename': '%s.py',
        'serializer': 'python',
    }
}

def export(request, admin_site, model_name, app_label, format='csv'):
    if not request.user.is_staff:
        return HttpResponseForbidden()

    if not format in ALLOWED_EXPORT_TYPES:
        raise Http404('%s is not a supported format.' % format)

    model = get_model(app_label, model_name)
    model_admin = None

    for entry in admin_site._registry:
        if entry._meta.object_name == model._meta.object_name:
            model_admin = admin_site._registry[entry]

    if model_admin == None:
        raise Http404('ModelAdmin for model %s.%s not found' % (app_label, model_name))

    cl = ChangeList(request, model, list(model_admin.list_display), model_admin.list_display_links,
                    model_admin.list_filter, model_admin.date_hierarchy, model_admin.search_fields,
                    model_admin.list_select_related, model_admin.list_per_page, model_admin.list_editable,
                    model_admin)
    cl.formset = None

    c = RequestContext(request)
    if 'template' in ALLOWED_EXPORT_TYPES[format]:
        rows = []
        headers = []

        for field in model._meta.fields:
            headers.append(field.name)

        rows.append(headers)

        for record in cl.query_set:
            column = []

            for field in headers:
                val = getattr(record, field)

                if callable(val):
                    val = val()

                val = smart_str(val)
                column.append(val)

            rows.append(column)

        t = loader.get_template(ALLOWED_EXPORT_TYPES[format]['template'])
        c['rows'] = rows
        responseContents = t.render(c)
    elif 'serializer' in ALLOWED_EXPORT_TYPES[format]:
        responseContents = serialize(ALLOWED_EXPORT_TYPES[format]['serializer'], cl.query_set.all())
    else:
        raise Http404('Export type for %s must have value for template or serializer' % format)

    response = HttpResponse(responseContents, mimetype=ALLOWED_EXPORT_TYPES[format]['mimetype'])
    response['Content-Disposition'] = 'attachment; filename=%s' % (ALLOWED_EXPORT_TYPES[format]['filename'] % slugify(model_name))

    return response

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

Dzjim (on November 24, 2009):

Can you give an example of how to implement this code? (url pattern example)

Thx!!!

#

monokrome (on December 2, 2009):

First of all, you will need to import django.admin After you import django.admin, you can then import your view. Don't use a string name, because admin_view wont accept a string happily.

Add the following to your URL conf, and you are done:

(r'^export/(?P<model_name>.)/(?P<app_label>.)/(?P<format>.*)/$', admin.site.admin_view(export), {'admin_site': admin.site}),

After this, create a new template in admin/export. Call this template "csv", and provide it the following code:

{% for row in rows %}{% for column in row %}{{ column|addslashes }},{%endfor%} {% endfor %}

This template is very sensitive, so make sure that all of it is on line 1 except for the last {% endfor %}, or your CSV files will be impoperly formatted.

This should be all that you need to get this snippet rolling.

Hope it helps!

#

z81 (on January 25, 2010):

Dzjim - could you post the change_list.html again - the above link is dead...

thx

#

Kludge (on March 18, 2010):

Yes, some more direction for implementing this into the admin site would be very helpful to me, e.g. what I would put into a template. thx

#

Pete (on August 9, 2011):

Could you provide the correct code - your statemetn shows

HTML_REMOVED

instead? Guess thats not intended?

(r'^export/(?P[HTML_REMOVED].)/(?P[HTML_REMOVED].)/(?P[HTML_REMOVED].*)/$', admin.site.admin_view(export), {'admin_site': admin.site}),

#

Please login first before commenting.