I am using django import-export and ImportExportModelAdmin
to import data from a file to the database from the admin interface.
Below is the model resource i use:
class ImportedBetResource(resources.ModelResource):
date = fields.Field(column_name='Date',
attribute='date',
widget=DateWidget(format="%d/%m/%Y"))
time = fields.Field(column_name='Time',
attribute='time',
widget=TimeWidget(format="%H:%M"))
sport = fields.Field(column_name='Sport',
attribute='sport',
widget=ForeignKeyWidget(Sport, 'name'))
country = fields.Field(column_name='Country',
attribute='country',
widget=ForeignKeyWidget(Country, 'name'))
bookie = fields.Field(column_name='Bookie',
attribute='bookie',
widget=ForeignKeyWidget(Bookie, 'name'))
currency = fields.Field(column_name='Currency',
attribute='stake_currency',
widget=ForeignKeyWidget(Currency, 'name'))
odds = fields.Field(column_name="Odds",
attribute="odds",
widget=DecimalWidget())
status = fields.Field(column_name='Status',
attribute='status',
widget=ForeignKeyWidget(Status, 'name'))
class Meta:
model = Bet
fields = ("id", "date", "time", "sport",
"country",
"competition", "home",
"visitor",
"bookie", "bet", "stake",
"currency",
"odds", "status")
clean_model_instances = True
@classmethod
def field_from_django_field(self, field_name, django_field, readonly):
"""
Returns a Resource Field instance for the given Django model field.
"""
FieldWidget = self.widget_from_django_field(django_field)
widget_kwargs = self.widget_kwargs_for_field(field_name)
field = fields.Field(attribute=field_name, column_name=field_name.replace("__name", "").title(),
widget=FieldWidget(**widget_kwargs), readonly=readonly)
return field
This is a screenshot of the import view from the documentation:
You can see the text "This importer will import the following fields" followed by the fields names.
In my case, the explicitly defined fields appear first, ex.:
country = fields.Field(column_name='Country',
attribute='country',
widget=ForeignKeyWidget(Country, 'name'))
and then the remaining fields defined in class Meta fields
:
This importer will import the following fields: Date, Time, Sport, Country, Bookie, Currency, Odds, Status, Id, Competition, Home, Visitor, Bet, Stake
The issue is that the order of fields don't follow the order of fields in my file and the data get scrambled.
This only happens when there are errors in the file.
Add the export_order option to your resources' Meta field like so:
class Meta:
model = Bet
fields = ("id", "date", "time", "sport",
"country",
"competition", "home",
"visitor",
"bookie", "bet", "stake",
"currency",
"odds", "status")
clean_model_instances = True
export_order = ["Date", "Time", "Sport", "Country",
"Bookie", "Currency", "Odds", "Status",
"Id", "Competition", "Home", "Visitor",
"Bet", "Stake"]
(or in whatever preferred order you would like) and django-import-export will import your stated fields accordingly! The reason why this works is that export_order is called by get_fields() which in turn is called by get_import_fields() as well as get_export_fields() affecting the entire workflows of both processes.
def export_order = None
def get_fields(self, **kwargs):
"""
Returns fields sorted according to
:attr:`~import_export.resources.ResourceOptions.export_order`.
"""
return [self.fields[f] for f in self.get_export_order()]
def get_import_fields(self):
return self.get_fields()
def get_export_fields(self):
return self.get_fields()
def import_obj(self, obj, data, dry_run):
"""
Traverses every field in this Resource and calls
:meth:`~import_export.resources.Resource.import_field`. If
``import_field()`` results in a ``ValueError`` being raised for
one of more fields, those errors are captured and reraised as a single,
multi-field ValidationError."""
errors = {}
for field in self.get_import_fields():
if isinstance(field.widget, widgets.ManyToManyWidget):
continue
try:
self.import_field(field, obj, data)
except ValueError as e:
errors[field.attribute] = ValidationError(
force_text(e), code="invalid")
if errors:
raise ValidationError(errors)
Above are excerpts from import_export.resources.py. For further clarification, I would also recommend the import data workflow documentation and methods for import_export's resources.
I hope this can be of help!