Source code for diskette.core.serializers.dumpdata
import json
from pathlib import Path
from io import StringIO
from django.core import management
from django.template.defaultfilters import filesizeformat
from ...utils.loggers import NoOperationLogger
from ..bases import BaseFileSizeAbstract
[docs]
class DumpdataSerializerAbstract(BaseFileSizeAbstract):
"""
Dump data serializer is in charge to serialize applications with Django dumpdata
command.
For now, this is JSON format only, 'format' option may be implemented later.
"""
COMMAND_NAME = "dumpdata"
COMMAND_TEMPLATE = "{executable}{cmd} {options}"
[docs]
def get_command_name(self, application):
"""
Return effective command name to use.
Either the application defines a custom command or this will be the default one
from ``DumpdataSerializerAbstract.COMMAND_NAME``.
Arguments:
application (ApplicationConfig): Application object.
Returns:
string: Command name.
"""
return getattr(application, "dump_command", None) or self.COMMAND_NAME
[docs]
def command(self, application, destination=None, indent=None):
"""
Build a command line to use ``dumpdata``.
Arguments:
application (ApplicationConfig): Application object.
Keyword Arguments:
destination (Path): The file path where to write dumped data.
indent (integer): Indentation level in data dumps.
Returns:
string: Command line to dump application datas.
"""
options = []
if indent:
options.append("--indent={}".format(indent))
if application.models:
options.append(" ".join(application.models))
if application.natural_foreign:
options.append("--natural-foreign")
if application.natural_primary:
options.append("--natural-primary")
if application.use_base_manager:
options.append("--all")
if application.is_drain:
options.append(" ".join([
"--exclude {}".format(item)
for item in application.excludes
]))
if destination:
options.append("--output={}".format(
str(Path(destination) / application.filename)
))
cmd = self.get_command_name(application)
return self.COMMAND_TEMPLATE.format(
cmd=cmd,
executable=self.executable,
name=application.name,
options=" ".join(options),
)
[docs]
def call(self, application, destination=None, indent=None, traceback=False,
check=False):
"""
Programmatically use the Django ``dumpdata`` command to dump application.
Arguments:
application (ApplicationConfig): Application object.
Keyword Arguments:
destination (Path): The file path where to write dumped data.
indent (integer): Indentation level in data dumps.
traceback (boolean): If enabled, Django will output the full traceback when
a dump raise an error. On default this is disabled and Django will
silently hide exception tracebacks.
check (boolean): Perform operations without writing or querying anything.
Returns:
string: A JSON payload of call results. On default, this is the JSON
output from dumpdata. However if destination has been given, dumpdata
has written output to a file and so the returned JSON will just be a
dictionnary with an item ``destination`` with written file path.
"""
options = application.as_options()
models = options.pop("models")
filename = options.pop("filename")
use_base_manager = options.pop("use_base_manager")
# Build args for command
if destination:
options["output"] = destination / filename
if indent:
options["indent"] = indent
if use_base_manager:
self.logger.debug("- Custom model manager is disabled")
options["all"] = use_base_manager
# Diskette never use 'excludes' for common applications
excludes = options.pop("excludes")
if application.is_drain:
options["exclude"] = excludes
if traceback:
options["traceback"] = True
self.logger.info("Dumping data for application '{}'".format(application.name))
if models:
self.logger.debug("- Including: {}".format(", ".join(models)))
if excludes:
self.logger.debug("- Excluding: {}".format(", ".join(excludes)))
if check:
return {"models": models, "options": options}
# Execute command without output guided to string buffer
out = StringIO()
management.call_command(
self.get_command_name(application),
models,
stdout=out,
**options
)
# If the file has a destination, write to the FS, write the destination path
# onto the application object
if destination:
out.close()
application._written = options["output"]
self.logger.debug(
"- Written file: {name} ({size})".format(
name=filename,
size=filesizeformat(self.get_file_size(options["output"])),
)
)
return json.dumps({"destination": str(application._written)})
# No destination to write just write it into the string buffer
content = out.getvalue()
out.close()
return content
[docs]
class DumpdataSerializer(DumpdataSerializerAbstract):
"""
Concrete basic implementation for ``StorageMixin``.
Keyword Arguments:
executable (string): A path to prefix commands, commonly the path to
django-admin (or equivalent). This path will suffixed with a single space
to ensure separation with command arguments.
logger (object): Instance of a logger object to use. Logger object must
implement common logging message methods (like error, info, etc..). See
``diskette.utils.loggers`` for available loggers. If not given, a dummy
logger will be used that ignores any messages and won't output anything.
"""
def __init__(self, executable=None, logger=None):
self.executable = executable + " " if executable else ""
self.logger = logger or NoOperationLogger()