For example purposes, we'll use a simplified book app. Here is our
models.py
:
# app/models.py class Author(models.Model): name = models.CharField(max_length=100) def __unicode__(self): return self.name class Category(models.Model): name = models.CharField(max_length=100) def __unicode__(self): return self.name class Book(models.Model): name = models.CharField('Book name', max_length=100) author = models.ForeignKey(Author, blank=True, null=True) author_email = models.EmailField('Author email', max_length=75, blank=True) imported = models.BooleanField(default=False) published = models.DateField('Published', blank=True, null=True) price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) categories = models.ManyToManyField(Category, blank=True) def __unicode__(self): return self.name
To integrate django-import-export with our Book
model, we will create a
:class:`~import_export.resources.ModelResource` class in admin.py
that will
describe how this resource can be imported or exported:
# app/admin.py from import_export import resources from core.models import Book class BookResource(resources.ModelResource): class Meta: model = Book
Now that we have defined a :class:`~import_export.resources.ModelResource` class, we can export books:
>>> from app.admin import BookResource >>> dataset = BookResource().export() >>> print dataset.csv id,name,author,author_email,imported,published,price,categories 2,Some book,1,,0,2012-12-05,8.85,1
By default :class:`~import_export.resources.ModelResource` introspects model fields and creates :class:`~import_export.fields.Field`-attributes with an appropriate :class:`~import_export.widgets.Widget` for each field.
To affect which model fields will be included in an import-export
resource, use the fields
option to whitelist fields:
class BookResource(resources.ModelResource): class Meta: model = Book fields = ('id', 'name', 'price',)
Or the exclude
option to blacklist fields:
class BookResource(resources.ModelResource): class Meta: model = Book exclude = ('imported', )
An explicit order for exporting fields can be set using the export_order
option:
class BookResource(resources.ModelResource): class Meta: model = Book fields = ('id', 'name', 'author', 'price',) export_order = ('id', 'price', 'author', 'name')
The default field for object identification is id
, you can optionally set which fields are used as the id
when importing:
class BookResource(resources.ModelResource): class Meta: model = Book import_id_fields = ('isbn',) fields = ('isbn', 'name', 'author', 'price',)
When defining :class:`~import_export.resources.ModelResource` fields it is possible to follow model relationships:
class BookResource(resources.ModelResource): class Meta: model = Book fields = ('author__name',)
Note
Following relationship fields sets field
as readonly, meaning
this field will be skipped when importing data.
By default all records will be imported, even if no changes are detected.
This can be changed setting the skip_unchanged
option. Also, the report_skipped
option
controls whether skipped records appear in the import Result
object, and if using the admin
whether skipped records will show in the import preview page:
class BookResource(resources.ModelResource): class Meta: model = Book skip_unchanged = True report_skipped = False fields = ('id', 'name', 'price',)
.. seealso:: :doc:`/api_resources`
It is possible to override a resource field to change some of its options:
from import_export.fields import Field class BookResource(resources.ModelResource): published = Field(attribute='published', column_name='published_date') class Meta: model = Book
Other fields that don't exist in the target model may be added:
from import_export.fields import Field class BookResource(resources.ModelResource): myfield = Field(column_name='myfield') class Meta: model = Book
.. seealso:: :doc:`/api_fields` Available field types and options.
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, dehydrate_<fieldname>
method should be defined:
from import_export.fields import Field class BookResource(resources.ModelResource): full_title = Field() class Meta: model = Book def dehydrate_full_title(self, book): return '%s by %s' % (book.name, book.author.name)
A :class:`~import_export.resources.ModelResource` creates a field with a
default widget for a given field type. If the widget should be initialized
with different arguments, set the widgets
dict.
In this example widget, the published
field is overriden to use a
different date format. This format will be used both for importing
and exporting resource.
class BookResource(resources.ModelResource): class Meta: model = Book widgets = { 'published': {'format': '%d.%m.%Y'}, }
.. seealso:: :doc:`/api_widgets` available widget types and options.
Let's import some data!
>>> import tablib
>>> from import_export import resources
>>> from core.models import Book
>>> book_resource = resources.modelresource_factory(model=Book)()
>>> dataset = tablib.Dataset(['', 'New book'], headers=['id', 'name'])
>>> result = book_resource.import_data(dataset, dry_run=True)
>>> print result.has_errors()
False
>>> result = book_resource.import_data(dataset, dry_run=False)
In the fourth line we use :func:`~import_export.resources.modelresource_factory` to create a default :class:`~import_export.resources.ModelResource`. The ModelResource class created this way is equal to the one shown in the example in section :ref:`base-modelresource`.
In fifth line a :class:`~tablib.Dataset` with columns id
and name
, and one book entry, are created. A field for a primary key field (in this case, id
) always needs to be present.
In the rest of the code we first pretend to import data using
:meth:`~import_export.resources.Resource.import_data` and dry_run
set,
then check for any errors and actually import data this time.
.. seealso:: :doc:`/import_workflow` for a detailed description of the import workflow and its customization options.
To delete objects during import, implement the :meth:`~import_export.resources.Resource.for_delete` method on your :class:`~import_export.resources.Resource` class.
The following is an example resource which expects a delete
field in the
dataset. An import using this resource will delete model instances for rows
that have their column delete
set to 1
:
class BookResource(resources.ModelResource): delete = fields.Field(widget=widgets.BooleanWidget()) def for_delete(self, row, instance): return self.fields['delete'].clean(row) class Meta: model = Book
To hook in the import export workflow, you can connect to post_import
, post_export
signals:
from django.dispatch import receiver from import_export.signals import post_import, post_export @receiver(post_import, dispatch_uid='balabala...') def _post_import(model, **kwargs): # model is the actual model instance which after import pass @receiver(post_export, dispatch_uid='balabala...') def _post_export(model, **kwargs): # model is the actual model instance which after export pass
Admin integration is achieved by subclassing :class:`~import_export.admin.ImportExportModelAdmin` or one of the available mixins (:class:`~import_export.admin.ImportMixin`, :class:`~import_export.admin.ExportMixin`, :class:`~import_export.admin.ImportExportMixin`):
# app/admin.py from import_export.admin import ImportExportModelAdmin class BookAdmin(ImportExportModelAdmin): resource_class = BookResource
Another approach to exporting data is by subclassing :class:`~import_export.admin.ImportExportActionModelAdmin` which implements export as an admin action. As a result it's possible to export a list of objects selected on the change list page:
# app/admin.py from import_export.admin import ImportExportActionModelAdmin class BookAdmin(ImportExportActionModelAdmin): pass
.. seealso:: :doc:`/api_admin` available mixins and options.