DEV Community

Cover image for Django Import Export From Basic To Advance
Areeba Seher
Areeba Seher

Posted on • Originally published at letscodemore.com

Django Import Export From Basic To Advance

Table of Content

  • Installation and configuration
  • Models
  • Resources
  • Exporting Data
  • Exporting Data as JSON
  • Exporting Data as CSV
  • Data Filtering + Exporting Data
  • Dealing with the model relationship
  • Foreign Key Relationship
  • Method 1: Using ForeignKeyWidget.
  • Method 2: Using fields
  • Many To Many Key Relationships
  • Method 1: By data manipulation on export
  • Method 2: By adding ManyToManyWidget
  • Advanced data manipulation on export.
  • Adding new columns
  • Changing headers before exporting
  • Export order
  • Admin Integration

django-import-export is a library used to handle importing and exporting of data. This package supports multiple formats.

  1. csv
  2. xls
  3. xlsx
  4. tsv
  5. ods
  6. json
  7. yml
  8. html This Library also has a Django admin integration.

For this article, I am using django==4.0 and django-import-export==2.9.0

Installation and configuration

pip install django-import-export
Enter fullscreen mode Exit fullscreen mode

Update your settings.py file.

INSTALLED_APPS = [
    .....
    'import_export',
]
Enter fullscreen mode Exit fullscreen mode

Models.

Now add our models. Here we have 3 simple models. I am using Foreign Key and Many to Many relations to cover these in this article.

# models.py
from django.db import models


class Author(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Book(models.Model):
    name = models.CharField('Book name', max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published = models.DateField('Published')
    categories = models.ManyToManyField(Category)

    def __str__(self):
        return self.name
Enter fullscreen mode Exit fullscreen mode

Now run migrations.

Resources

Create a new file resources.py in your app. In this file, we will add the Model Resource classes which are similar to how Django handles forms.py.

# resources.py
from import_export import resources
from .models import Author, Category, Book


class BookResource(resources.ModelResource):
    class Meta:
        model = Book
Enter fullscreen mode Exit fullscreen mode

This is the simplest configuration. We can add more, like fields, and exclude in Meta just like forms.py configuration. We will discuss it below.

Exporting data

Run python manage.py shell. It will open the shell.

Exporting Data as JSON.

from app.resources import BookResource

book_resource = BookResource()
data = book_resource.export()
data.json
Enter fullscreen mode Exit fullscreen mode

Output:

[
    {"id": 1, "name": "Django for APIs", "author": 1, "published": "2022-09-16", "categories": "2"},
    {"id": 2, "name": "Beginning Django E-Commerce", "author": 2, "published": "2022-09-16", "categories": "1,3"},
    {"id": 3, "name": "Django Unleashed", "author": 3, "published": "2022-09-16", "categories": "1,2"},
    {"id": 4, "name": "Django Design Patterns and Best Practices", "author": 4, "published": "2022-09-16", "categories": "1,4"}
]
Enter fullscreen mode Exit fullscreen mode

Exporting Data as CSV.

from app.resources import BookResource

book_resource = BookResource()
data = book_resource.export()
data.csv
Enter fullscreen mode Exit fullscreen mode

Output:

id,name,author,published,categories
1,Django for APIs,1,2022-09-16,2
2,Beginning Django E-Commerce,2,2022-09-16,"1,3"
3,Django Unleashed,3,2022-09-16,"1,2"
4,Django Design Patterns and Best Practices,4,2022-09-16,"1,4"
Enter fullscreen mode Exit fullscreen mode

Data Filtering + Exporting Data.

We can also export the filtered data.

from app.models import Book
from app.resources import BookResource


query = Book.objects.filter(name="Django for APIs")
book_resource = BookResource()
data = book_resource.export(query)
data.json
Enter fullscreen mode Exit fullscreen mode

Output:

[
    {"id": 1, "name": "Django for APIs", "author": 1, "published": "2022-09-16", "categories": "2"}
]
Enter fullscreen mode Exit fullscreen mode

Views and URLs.

# views.py
from django.http import HttpResponse
from .resources import BookResource


def export_csv(request):
    book_resource = BookResource()
    data = book_resource.export()
    response = HttpResponse(data.csv, content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="books.csv"'
    return response
Enter fullscreen mode Exit fullscreen mode
# urls.py

from django.urls import path
from .views import export_csv

urlpatterns = [
    path('export-csv', export_csv, name='export_csv')
]
Enter fullscreen mode Exit fullscreen mode

Go to this URL:

http://127.0.0.1:8000/export-csv (It will download the books.csv file)

Image description
Note:
For json export use content_type='application/json' and filename=books.json

For excel (xslx) export use content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' and filename=books.xlsx

You can check more content_type from here:

Dealing with the model relationship.

When defining ModelResource fields it is possible to follow model relationships:

1) Foreign Key Relationship.

In the above CSV file picture, you can see that in the author column we have author ids like 1,2,3,4, not the author name.

1. Method 1: Using ForeignKeyWidget.

class import_export.widgets.ForeignKeyWidget(model, field='pk', *args, **kwargs)

fields = 'pk' is the default lookup criterion for the lookup field. But we can customize it. As in our example, we are using field = "name" as a lookup field.

I prefer this method because it's a widget so you can use this widget in any resource class.

# resources.py

from import_export import resources
from .models import Author, Category, Book
from import_export.fields import Field
from import_export.widgets import ForeignKeyWidget

class BookResource(resources.ModelResource):

    author = Field(
        column_name='author',
        attribute='author',
        widget=ForeignKeyWidget(model=Author, field='name'))

    class Meta:
        model = Book
Enter fullscreen mode Exit fullscreen mode

Output

name,published,categories,author
Django for APIs,2022-09-16,2,William S. Vincent
Beginning Django E-Commerce,2022-09-16,"1,3",James McGaw
Django Unleashed,2022-09-16,"1,2",Andrew Pinkham
Django Design Patterns and Best Practices,2022-09-16,"1,4",Arun Ravindran
Enter fullscreen mode Exit fullscreen mode

2. Method 2: Using fields

Adding author__name in fields under Meta will give the author name instead of the author id.

# resources.py

class BookResource(resources.ModelResource):
    class Meta:
        model = Book
        fields = ('name', 'author__name', 'published', 'categories')
Enter fullscreen mode Exit fullscreen mode

Output:

name,published,categories,author__name
Django for APIs,2022-09-16,2,William S. Vincent
Beginning Django E-Commerce,2022-09-16,"1,3",James McGaw
Django Unleashed,2022-09-16,"1,2",Andrew Pinkham
Django Design Patterns and Best Practices,2022-09-16,"1,4",Arun Ravindran
Enter fullscreen mode Exit fullscreen mode

Read more from here. How to export Foreign key relation in django

2) Many To Many Key Relationships.

If we check the output then we observed that the categories column contains ids of categories like 2, "1,3" etc

We have 2 methods to do this.

1) Method 1: By data manipulation on export:

We can manipulate data (any field) before exporting. We will perform some more manipulation in this article.

Not all data can be easily extracted from an object/model attribute. In order to turn complicated data model into a (generally simpler) processed data structure on export, dehydrate_ method should be defined: source: Documentation

# resources.py

class BookResource(resources.ModelResource):

    def dehydrate_categories(self, book):
        data = []
        for i in book.categories.all():
            data.append(i.name)
        joined_string = ",".join(data)
        return str(joined_string)

    class Meta:
        model = Book
Enter fullscreen mode Exit fullscreen mode

Output:

id,name,author,published,categories
1,Django for APIs,1,2022-09-16,Coding
2,Beginning Django E-Commerce,2,2022-09-16,"Programming,ecommerce"
3,Django Unleashed,3,2022-09-16,"Programming,Coding"
4,Django Design Patterns and Best Practices,4,2022-09-16,"Programming,Best practices"
Enter fullscreen mode Exit fullscreen mode

2) Method 2: By adding ManyToManyWidget:

class import_export.widgets.ManyToManyWidget(model, separator=None, field=None, *args, **kwargs)

I prefer this method.

# resources.py

from import_export import resources
from .models import Author, Category, Book
from import_export.widgets import ManyToManyWidget
from import_export.fields import Field


class BookResource(resources.ModelResource):
    categories = Field(
        column_name='categories', attribute='categories',
        widget=ManyToManyWidget(model=Category, separator=',', field='name'))

    class Meta:
        model = Book
Enter fullscreen mode Exit fullscreen mode

Output

categories,id,name,author,published
Coding,1,Django for APIs,1,2022-09-16
"Programming,ecommerce",2,Beginning Django E-Commerce,2,2022-09-16
"Programming,Coding",3,Django Unleashed,3,2022-09-16
"Programming,Best practices",4,Django Design Patterns and Best Practices,4,2022-09-16
Enter fullscreen mode Exit fullscreen mode

Read in detail from here.

Advanced data manipulation on export.

Adding new columns.

Let's take an example. You have 2 column names or fields i.e first name and last name. And you want to add a new column "Full Name" by combining the first and last name in the exported file.
In our case, we are adding 2 new columns full_title and description.

# resources.py

class BookResource(resources.ModelResource):

    full_title = Field(column_name='Full Title')
    description = Field()

    def dehydrate_full_title(self, book):
        book_name = getattr(book, "name", "unknown")
        author_name = getattr(book.author, "name", "unknown")
        return '%s by %s' % (book_name, author_name)

    def dehydrate_description(self, book):
        book_name = getattr(book, "name", "unknown")
        author_name = getattr(book.author, "name", "unknown")
        published = getattr(book, "published", "unknown")
        return "%s is published by %s in %s" % (book_name, author_name, published)


    def dehydrate_categories(self, book):
        data = []
        for i in book.categories.all():
            data.append(i.name)
        joined_string = ",".join(data)
        return str(joined_string)

    class Meta:
        model = Book
Enter fullscreen mode Exit fullscreen mode

Output:

Full Title,description,id,name,author,published,categories
Django for APIs by William S. Vincent,Django for APIs is published by William S. Vincent in 2022-09-16,1,Django for APIs,1,2022-09-16,Coding
Beginning Django E-Commerce by James McGaw,Beginning Django E-Commerce is published by James McGaw in 2022-09-16,2,Beginning Django E-Commerce,2,2022-09-16,"Programming,ecommerce"
Django Unleashed by Andrew Pinkham,Django Unleashed is published by Andrew Pinkham in 2022-09-16,3,Django Unleashed,3,2022-09-16,"Programming,Coding"
Django Design Patterns and Best Practices by Arun Ravindran,Django Design Patterns and Best Practices is published by Arun Ravindran in 2022-09-16,4,Django Design Patterns and Best Practices,4,2022-09-16,"Programming,Best practices"
Enter fullscreen mode Exit fullscreen mode

Changing headers before exporting.

We can also change the headers before exporting our data.

# resources.py

from import_export import resources
from .models import Author, Category, Book
from .widgets import CustomManyToManyWidget
from import_export.fields import Field


class BookResource(resources.ModelResource):

    def get_export_headers(self):
        headers = super().get_export_headers()
        for i, h in enumerate(headers):
            if h == 'author':
                headers[i] = "Author"
            if h == 'name':
                headers[i] = "Book Name"
        return headers

    class Meta:
        model = Book
Enter fullscreen mode Exit fullscreen mode

Output:

id,Book Name,Author,published,categories
1,Django for APIs,1,2022-09-16,2
2,Beginning Django E-Commerce,2,2022-09-16,"1,3"
3,Django Unleashed,3,2022-09-16,"1,2"
4,Django Design Patterns and Best Practices,4,2022-09-16,"1,4"
Enter fullscreen mode Exit fullscreen mode

Export Order.

You can set export_order in the Meta class.

# resources.py

class Meta:
        model = Book
        export_order = (
            'name', 'author', 'full_title', 'published', 'categories', 'description'
        )
Enter fullscreen mode Exit fullscreen mode

Output:

name,author,Full Title,published,categories,description
Django for APIs,William S. Vincent,Django for APIs by William S. Vincent,2022-09-16,Coding,Django for APIs is published by William S. Vincent in 2022-09-16
Beginning Django E-Commerce,James McGaw,Beginning Django E-Commerce by James McGaw,2022-09-16,"Programming,ecommerce",Beginning Django E-Commerce is published by James McGaw in 2022-09-16
Django Unleashed,Andrew Pinkham,Django Unleashed by Andrew Pinkham,2022-09-16,"Programming,Coding",Django Unleashed is published by Andrew Pinkham in 2022-09-16
Django Design Patterns and Best Practices,Arun Ravindran,Django Design Patterns and Best Practices by Arun Ravindran,2022-09-16,"Programming,Best practices",Django Design Patterns and Best Practices is published by Arun Ravindran in 2022-09-16
Enter fullscreen mode Exit fullscreen mode

You can also use exclude in the Meta class. I will recommend you go through the documentation. Because django-import-export documentation is really good and easy to understand.

Admin Integration.

# admin.py

from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from .models import (Author, Category, Book)
from .resources import BookResource


admin.site.register(Author)
admin.site.register(Category)


class BookAdmin(ImportExportModelAdmin):
    resource_class = BookResource

admin.site.register(Book, BookAdmin)
Enter fullscreen mode Exit fullscreen mode

Then go to the admin panel. You will see the following options in the admin panel under Book Model.

Image description
You can select a different format and press submit. Your data will be exported in your required format.

Image description
That's it for now. If you like this article then please show some love in the comment section or by supporting the content. You can also suggest more articles in the comment section. I will definitely write your suggested articles.
Thank you.

If you like my post then you can support me by buying me a coffee ☕

Buy Me A Coffee

Happy Coding.

This artical is originally published here. https://www.letscodemore.com/

Top comments (0)