-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
295 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
import_export_extensions/api/serializers/import_job_details.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import typing | ||
from itertools import zip_longest | ||
|
||
from rest_framework import serializers | ||
|
||
from import_export.results import RowResult | ||
|
||
from ... import models | ||
|
||
|
||
class ImportParamsSerializer(serializers.Serializer): | ||
"""Serializer for representing import parameters.""" | ||
data_file = serializers.FileField() | ||
resource_path = serializers.CharField() | ||
resource_kwargs = serializers.CharField() | ||
|
||
|
||
class ImportDiffSerializer(serializers.Serializer): | ||
"""Serializer for representing importing rows diff.""" | ||
previous = serializers.CharField(allow_blank=True, allow_null=True) | ||
current = serializers.CharField(allow_blank=True, allow_null=True) | ||
|
||
|
||
class ImportRowSerializer(serializers.Serializer): | ||
"""Serializer for representing importing rows. | ||
Used to generate correct openapi spec. | ||
""" | ||
operation = serializers.CharField() | ||
parsed_fields = serializers.ListField( | ||
child=ImportDiffSerializer(allow_null=True), | ||
allow_null=True, | ||
) | ||
|
||
|
||
class ImportingDataSerializer(serializers.Serializer): | ||
"""Serializer for representing importing data.""" | ||
headers = serializers.ListField( | ||
child=serializers.CharField(), | ||
) | ||
rows = serializers.ListField( | ||
child=ImportRowSerializer(), | ||
) | ||
|
||
def to_representation(self, instance: models.ImportJob): | ||
"""Return dict with import details.""" | ||
if instance.import_status not in models.ImportJob.success_statuses: | ||
return super().to_representation(self.get_initial()) | ||
|
||
rows = [] | ||
resource = instance.resource | ||
for row in instance.result.rows: | ||
# errors displayed in input_error.row_errors(InputErrorSerializer) | ||
if row.import_type == RowResult.IMPORT_TYPE_ERROR: | ||
continue | ||
|
||
original_fields = [ | ||
resource.export_field(f, row.original) if row.original else "" | ||
for f in resource.get_user_visible_fields() | ||
] | ||
current_fields = [ | ||
resource.export_field(f, row.instance) | ||
for f in resource.get_user_visible_fields() | ||
] | ||
|
||
rows.append({ | ||
"operation": row.import_type, | ||
"parsed_fields": [ | ||
{ | ||
"previous": v1, | ||
"current": v2, | ||
} for v1, v2 in zip_longest(original_fields, current_fields, fillvalue="") | ||
], | ||
}) | ||
|
||
importing_data = { | ||
"headers": instance.result.diff_headers, | ||
"rows": rows, | ||
} | ||
return super().to_representation(importing_data) | ||
|
||
|
||
class TotalsSerializer(serializers.Serializer): | ||
"""Serializer to represent import totals.""" | ||
new = serializers.IntegerField(allow_null=True, required=False) | ||
update = serializers.IntegerField(allow_null=True, required=False) | ||
delete = serializers.IntegerField(allow_null=True, required=False) | ||
skip = serializers.IntegerField(allow_null=True, required=False) | ||
error = serializers.IntegerField(allow_null=True, required=False) | ||
|
||
def to_representation(self, instance): | ||
"""Return dict with import totals.""" | ||
if instance.import_status not in models.ImportJob.results_statuses: | ||
return super().to_representation(self.get_initial()) | ||
return super().to_representation(instance.result.totals) | ||
|
||
|
||
class RowError(serializers.Serializer): | ||
"""Represent single row errors.""" | ||
line = serializers.IntegerField() | ||
error = serializers.CharField() | ||
row = serializers.ListField( | ||
child=serializers.CharField(), | ||
) | ||
|
||
|
||
class InputErrorSerializer(serializers.Serializer): | ||
"""Represent Input errors.""" | ||
base_errors = serializers.ListField( | ||
child=serializers.CharField(), | ||
) | ||
row_errors = serializers.ListField( | ||
child=serializers.ListField( | ||
child=RowError(), | ||
), | ||
) | ||
|
||
def to_representation(self, instance: models.ImportJob): | ||
"""Return dict with input errors.""" | ||
if instance.import_status not in models.ImportJob.results_statuses: | ||
return super().to_representation(self.get_initial()) | ||
|
||
input_errors: dict[str, list[typing.Any]] = { | ||
"base_errors": [], | ||
"row_errors": [], | ||
} | ||
|
||
if instance.result.base_errors: | ||
input_errors["base_errors"] = [ | ||
str(error.error) for error in instance.result.base_errors | ||
] | ||
|
||
if instance.result.row_errors(): | ||
for line, errors in instance.result.row_errors(): | ||
line_errors = [ | ||
{ | ||
"line": line, | ||
"error": str(error.error), | ||
"row": error.row.values(), | ||
} for error in errors | ||
] | ||
input_errors["row_errors"].append(line_errors) | ||
|
||
return super().to_representation(input_errors) | ||
|
||
|
||
class IsAllRowsShowField(serializers.BooleanField): | ||
"""Field for representing `all_rows_saved` value.""" | ||
|
||
def to_representation(self, instance): | ||
"""Return boolean if all rows shown in importing data.""" | ||
if instance.import_status not in models.ImportJob.success_statuses: | ||
return False | ||
return instance.result.total_rows == len(instance.result.rows) |
30 changes: 30 additions & 0 deletions
30
import_export_extensions/migrations/0006_importjob_input_errors_file.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Generated by Django 4.2.7 on 2024-01-15 10:40 | ||
|
||
from django.db import migrations, models | ||
import functools | ||
import import_export_extensions.models.tools | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("import_export_extensions", "0005_importjob_force_import"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="importjob", | ||
name="input_errors_file", | ||
field=models.FileField( | ||
help_text="File that contain failed rows", | ||
max_length=512, | ||
null=True, | ||
upload_to=functools.partial( | ||
import_export_extensions.models.tools.upload_file_to, | ||
*(), | ||
**{"main_folder_name": "import"} | ||
), | ||
verbose_name="Input errors file", | ||
), | ||
), | ||
] |
Oops, something went wrong.