Search code examples
djangodjango-import-export

DJango - Export Json Field in Model to CSV along with other fields


I am working on a DJango project, and in the admin I need to add an action which will export and download the contents of the model. I have successfully added the export action using import-export and it downloads the data just fine.

Currently I just subclass using

ImportExportActionModelAdmin

and it automatically shows the export option in the drop down menu.

But now the issue is, one of the fields in the model being downloaded is a JSON field and gets exported to csv as JSON itself, rightly so. I want ideas on how can i convert this JSON field into csv as well.

Sample data that gets downloaded in the CSV:

{u'course_name': u'ABC', u'notes': u'Test', u'contact_mode': u'Message', u'contact_no': u'9876543210', u'stud_count': u'600', u'date': u'2018-12-19T18:30:00.000Z', u'email': u'kj@test.com', u'exp11': u'YES'}

I did some reading and seems

import_export.widgets.JSONWidget 

can do the trick but am not sure how to implement this. Can some one give an example?

My Class that needs to be exported into CSV:

class Register(TimeStampedModel):
    email = models.EmailField(max_length=100)
    name = models.CharField(max_length=255)
    details = JSONField(null=True, blank=True, default={})

    def __str__(self):
        return '%s (%s)' % (self.name, self.email)

Thanks in advance.


Solution

  • I solved the issue, and here is how I did it for anyone who might need it.

    First import the following,

    from django.db import models
    from django.http import HttpResponse
    from django.contrib import admin
    from import_export.admin import ImportExportMixin
    import json
    import csv 
    

    Then subclass your model admin using ImportExportMixin and ModelAdmin and then add the required action as shown below.

    class PostAdmin(ImportExportMixin, admin.ModelAdmin):
        actions = [export_json_field,]
    

    Now, define the function to be called when the user selects this action on the admin page of the model

    def export_json_field(modeladmin, request, queryset):
        '''
        Exports the JSON fields in a model to csv file
        '''        
        #Create the httpResponse object with correct csv header
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="Json2Csv.csv"'
        writer = csv.writer(response)    
        count = 0
        # print(json.dumps(queryset[0].details))    
        for obj in queryset:                   
            #loop through all the fields in the current post object
            for field in obj._meta.fields:
                #find the fields with JSONField type
                if obj._meta.get_field(field.name).get_internal_type() == 'JSONField':
                    #get the contents of the json field and convert it into json format
                    detail = json.dumps(getattr(obj,field.name))
                    #detail = "'" + detail + "'"
                    detail_parsed = json.loads(str(detail))               
                    #lists to store the keys and values from the json
                    keys = []
                    values = []
                    #loop through each json row and make a list of the keys and values
                    for key, value in detail_parsed.items():
                        keys.append(key)
                        values.append(value)    
                    # write the values into csv file 
                    # keys form the column headers so write them only once
                    if count == 0:
                        writer.writerow(keys)
                        count += 1                
                    # write the values in each row
                    writer.writerow(values)                
        return response
    
    export_json_field.short_description = 'Export Json TO Csv'
    

    The last line gives a name to this action that is displayed in the dropdown box in the admin page (Export Json TO Csv)

    Finally, register the model admin

    admin.site.register(Post, PostAdmin)
    

    This will let you use the importexport functionality of the django-import-export library as well as define your own action within the same admin page.

    Hope it helps.