Skip to content

Handle Custom Export Format #118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ To exclude or disable file formats from the admin site, configure `IMPORT_EXPORT

IMPORT_EXPORT_CELERY_EXCLUDED_FORMATS = ["csv", "xls"]

Add Custom export file formats in the admin site
------------------------------------------------

To include custom file formats from the admin site, configure `IMPORT_EXPORT_CELERY_CUSTOM_FORMATS` django settings variable. This variable is a a list of string path to custom format classes.

::

IMPORT_EXPORT_CELERY_CUSTOM_FORMATS = ["path.to.custom_format.CustomFormat", "path.to.custom_format.CustomFormat2]

Customizing File Storage Backend
--------------------------------
Expand Down
11 changes: 10 additions & 1 deletion import_export_celery/admin_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.shortcuts import redirect

from .models import ExportJob

from .utils import get_formats
from . import tasks


Expand Down Expand Up @@ -53,6 +53,15 @@ def create_export_job_action(modeladmin, request, queryset):
),
site_of_origin=request.scheme + "://" + request.get_host(),
)

# Load the ExportJob if only one Resource
resource_choices = ej.get_resource_choices()
format_choices = get_formats()
if len(resource_choices) == 1 and len(format_choices) == 1:
ej.resource = resource_choices[0][0]
ej.format = format_choices[0].CONTENT_TYPE
ej.save()

rurl = reverse(
"admin:%s_%s_change"
% (
Expand Down
150 changes: 150 additions & 0 deletions import_export_celery/locale/fr/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Dan <[email protected]>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-17 20:55+0000\n"
"PO-Revision-Date: 2023-05-17 21:56+0100\n"
"Last-Translator: Daniel Pluth <[email protected]>\n"
"Language-Team: \n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.3.1\n"

#: import_export_celery/admin.py:12
msgid "Job status info"
msgstr "Statut de l'export"

#: import_export_celery/admin.py:22 import_export_celery/models/importjob.py:62
msgid "Name of model to import to"
msgstr "Nom du modèle à importer"

#: import_export_celery/admin_actions.py:20
msgid "Perform import"
msgstr "Effectuer l'importation"

#: import_export_celery/admin_actions.py:29
msgid "Perform dry import"
msgstr "Effectuer une importation à blanc"

#: import_export_celery/admin_actions.py:39
msgid "Run export job"
msgstr "Lancer le travail d'exportation"

#: import_export_celery/admin_actions.py:67
msgid "Export with celery"
msgstr "Exporter avec Celery"

#: import_export_celery/apps.py:7
msgid "Import Export Celery"
msgstr "Exports"

#: import_export_celery/models/exportjob.py:27
msgid "exported file"
msgstr "fichier exporté"

#: import_export_celery/models/exportjob.py:35
#: import_export_celery/models/importjob.py:30
msgid "Have we started processing the file? If so when?"
msgstr "Démarrage de l'export"

#: import_export_celery/models/exportjob.py:42
#: import_export_celery/models/importjob.py:67
msgid "Status of the job"
msgstr "Statut du travail"

#: import_export_celery/models/exportjob.py:48
msgid "Format of file to be exported"
msgstr "Format du fichier à exporter"

#: import_export_celery/models/exportjob.py:55
msgid "App label of model to export from"
msgstr "Nom de l'application du modèle à exporter"

#: import_export_celery/models/exportjob.py:60
msgid "Name of model to export from"
msgstr "Nom du modèle à exporter"

#: import_export_celery/models/exportjob.py:65
msgid "Resource to use when exporting"
msgstr "Ressource à utiliser lors de l'exportation"

#: import_export_celery/models/exportjob.py:71
msgid "JSON list of pks to export"
msgstr "Liste JSON des clés primaires à exporter"

#: import_export_celery/models/exportjob.py:76
msgid "Send me an email when this export job is complete"
msgstr "Envoyez-moi un email lorsque ce travail d'exportation est terminé"

#: import_export_celery/models/exportjob.py:81
msgid "Site of origin"
msgstr "Site d'origine"

#: import_export_celery/models/exportjob.py:87
msgid "Export job"
msgstr "Travail d'exportation"

#: import_export_celery/models/exportjob.py:88
msgid "Export jobs"
msgstr "Exports"

#: import_export_celery/models/importjob.py:22
msgid "File to be imported"
msgstr "Fichier à importer"

#: import_export_celery/models/importjob.py:37
msgid "Has the import been completed? If so when?"
msgstr "L'importation a-t-elle été complétée ? Si oui, quand ?"

#: import_export_celery/models/importjob.py:44
msgid "Format of file to be imported"
msgstr "Format du fichier à importer"

#: import_export_celery/models/importjob.py:49
msgid "Summary of changes made by this import"
msgstr "Résumé des changements effectués par cette importation"

#: import_export_celery/models/importjob.py:56
msgid "Errors"
msgstr "Erreurs"

#: import_export_celery/models/importjob.py:73
msgid "Import job"
msgstr "Travail d'importation"

#: import_export_celery/models/importjob.py:74
msgid "Import jobs"
msgstr "Travaux d'importation"

#: import_export_celery/tasks.py:61
#, python-format
msgid "Imported file has a wrong encoding: %s"
msgstr "Le fichier importé a un encodage incorrect : %s"

#: import_export_celery/tasks.py:68
#, python-format
msgid "Error reading file: %s"
msgstr "Erreur de lecture du fichier : %s"

#: import_export_celery/tasks.py:101
#, python-format
msgid ""
"Line: %s - %s\n"
"\t%s\n"
"%s"
msgstr ""
"Ligne : %s - %s\n"
"\t%s\n"
"%s"

#: import_export_celery/tasks.py:190
#, python-format
msgid "Import error %s"
msgstr "Erreur d'importation %s"
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 4.2 on 2024-04-12 14:09

from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

dependencies = [
("import_export_celery", "0010_auto_20231013_0904"),
]

operations = [
migrations.AddField(
model_name="exportjob",
name="created_at",
field=models.DateTimeField(
auto_now_add=True, default=django.utils.timezone.now
),
preserve_default=False,
),
migrations.AlterField(
model_name="exportjob",
name="id",
field=models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
migrations.AlterField(
model_name="importjob",
name="id",
field=models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
]
5 changes: 5 additions & 0 deletions import_export_celery/models/exportjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,15 @@ def __init__(self, *args, **kwargs):
default="",
)

created_at = models.DateTimeField(auto_now_add=True)

class Meta:
verbose_name = _("Export job")
verbose_name_plural = _("Export jobs")

def __str__(self):
return f"Export {self.model.title()} - par {self.author} - le {self.created_at.date()} - {self.job_status}"

def get_resource_class(self):
if self.resource:
return (
Expand Down
11 changes: 5 additions & 6 deletions import_export_celery/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def export_resource(self, *args, **kwargs):
change_job_status(
export_job,
"export",
f"Exporting row {self.row_number}/{qs_len}",
f"En cours ({self.row_number}/{qs_len} lignes)",
)
self.row_number += 1
return super().export_resource(*args, **kwargs)
Expand All @@ -238,11 +238,10 @@ def export_resource(self, *args, **kwargs):
data = resource.export(queryset)
format = get_format(export_job)
serialized = format.export_data(data)
change_job_status(export_job, "export", "Export complete")
filename = "{app}-{model}-{date}.{extension}".format(
app=export_job.app_label,
model=export_job.model,
date=str(timezone.now()),
change_job_status(export_job, "export", "Export terminé")
filename = "Export {model} - {date}.{extension}".format(
model=export_job.model.title(),
date=str(timezone.now().strftime("%Y-%m-%d-%H-%M-%S")),
extension=format.get_extension(),
)
if not format.is_binary():
Expand Down
17 changes: 16 additions & 1 deletion import_export_celery/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.conf import settings
from django.urls import reverse
from import_export.formats.base_formats import DEFAULT_FORMATS
from importlib import import_module

DEFAULT_EXPORT_JOB_COMPLETION_MAIL_SUBJECT = "Django: Export job completed"
DEFAULT_EXPORT_JOB_COMPLETION_MAIL_TEMPLATE = (
Expand All @@ -15,14 +16,28 @@
[],
)

IMPORT_EXPORT_CELERY_CUSTOM_FORMATS = getattr(settings, "IMPORT_EXPORT_CELERY_CUSTOM_FORMATS", [])

def get_formats():
custom_formats = get_custom_formats()

return [
format
for format in DEFAULT_FORMATS
if format.TABLIB_MODULE.split(".")[-1].strip("_")
not in IMPORT_EXPORT_CELERY_EXCLUDED_FORMATS
]
] + custom_formats

def get_custom_formats():
# Load custom formats if any
custom_formats = []
if IMPORT_EXPORT_CELERY_CUSTOM_FORMATS:
for formatxx in IMPORT_EXPORT_CELERY_CUSTOM_FORMATS:
target_module_directory, target_format_name = formatxx.rsplit('.', 1)
target_module = import_module(target_module_directory)
target_format = getattr(target_module, target_format_name)
custom_formats.append(target_format)
return custom_formats


def build_html_and_text_message(template_name, context={}):
Expand Down