Skip to main content

Django app that automates objects tree serialization recursively

Project description

Django auto-serializer

Django app that automates objects tree serialization recursively, without any declarations.

Define new classes for every Object serialization could sound a bit boring, I coded this app to do the things automagically. Django-auto-serializer will do for you:

  • Json serialization (export);
  • recursively serialize all FK childrens;
  • can ignore some children if you tell him how they are named (see examples above);
  • M2M auto serialization;
  • ignore or not autofields import/export (auto_now_add...);
  • regenerates unique if needed, the same for slugfields (change_uniques = True,);
  • Import a serialized Object tree, it will build up everything as before;

Setup

pip install git+https://github.com/peppelinux/django-auto-serializer.git

Usage Example

from my_app.models import MyModel

# get an object
myObj = MyModel.objects.first()

# object serialization
# A single object duplication
si = SerializableInstance(myObj)

#si.serialize_obj()
si.serialize_tree()
si.remove_duplicates()
# pprint(si.dict)

# Serialized entire tree, main object with childrens
si = SerializableInstance(myObj,
                          excluded_fields=['field1', 'field2'],
                          excluded_childrens = ['relatedObjClass1', 'relatedObjClass2'],
                          auto_fields = False,
                          change_uniques = True,
                          duplicate = True)
si.serialize_tree()
si.remove_duplicates()

Some coding hints

import pprint
# all the fields
myObj._meta._forward_fields_map

# childrens here
myObj._meta.fields_map
myObj._meta.related_objects

# another way with NestedObjects
from django.contrib.admin.utils import NestedObjects
from django.db import DEFAULT_DB_ALIAS

# get json with pk and autofilled fields as they are
from django.core import serializers
serializers.serialize('json', [myObj], ensure_ascii=False)

# serializers.serialize() relies on
model_to_dict(myObj)

pprint(sit.dict)
for i in sit.dict['childrens']:
    if i['model_name'] == 'ClassName':
        pprint(i)

tree_to_str = json.dumps(si.dict, indent=2)
jsonstr_to_dict = json.loads(tree_to_str)
pprint(jsonstr_to_dict )

Import dump

isi = ImportableSerializedInstance(si.dict)
isi.save()
print(isi.json())

A simple view to import a json dump

@user_passes_test(lambda u:u.is_staff)
def import_file(request):
    file_to_import = request.FILES.get('file_to_import')
    # content here
    url = reverse('admin:my_django_admin_url')
    if not file_to_import:
        return HttpResponseRedirect(url)
    if not file_to_import:
        # error message here
        pass
    jcont = json.loads(request.FILES['file_to_import'].read().decode(settings.DEFAULT_CHARSET))
    isi = ImportableSerializedInstance(jcont)
    isi.save()
    return HttpResponseRedirect(url)

Django admin action to duplicate or export an entire tree

import io
import json

from django.apps import apps
from django.contrib import messages
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE
from django.contrib.contenttypes.models import ContentType
from django.http.response import HttpResponse

from django_auto_serializer.auto_serializer import (SerializableInstance,
                                                    ImportableSerializedInstance)

from .models import *


def my_clone_func(modeladmin, request, queryset):
    for myObj in queryset:
        try:
            si = SerializableInstance(myObj)
            si.serialize_tree()
            si.remove_duplicates()
        except Exception as e:
            msg = '{} cloning failed: {}'
            messages.add_message(request, messages.WARNING,
                                 msg.format(myObj, e))
        try:
            isi = ImportableSerializedInstance(si.dict)
            isi.save()
        except Exception as e:
            msg = '{} cloning failed: {}'
            messages.add_message(request, messages.WARNING,
                                 msg.format(myObj, e))

        msg = '{} successfully cloned.'
        messages.add_message(request, messages.INFO,
                             msg.format(myObj))
my_clone_func.short_description = "Clone object and its configuration"


def download_obj_template(modeladmin, request, queryset):
    iofile = io.StringIO()
    obj_labels = []
    for myObj in queryset:
        try:
            si = SerializableInstance(myObj)
            st = si.serialize_tree()
            iofile.write(json.dumps(si.dict, indent=2))
        except Exception as e:
            msg = '{} cloning failed: {}'
            messages.add_message(request, messages.WARNING,
                                 msg.format(myObj, e))
        obj_labels.append(myObj.__str__())
    file_name = 'my_export{}.json'.format('_'.join(obj_labels))
    iofile.seek(0)
    response = HttpResponse(iofile.read())
    response['content_type'] = 'application/force-download'
    response['Content-Disposition'] = 'attachment; filename={}'.format(file_name)
    response['X-Sendfile'] = file_name
    return response
download_obj_template.short_description = "Download object json template"

Result (from a real NavigationBar object with items and items childs)

{'source_pk': 266,
 'duplicate': True,
 'app_name': 'cmsmenus',
 'model_name': 'NavigationBar',
 'object': {'created_by': 2,
  'created_by_id': 2,
  'is_active': True,
  'name': 'test'},
 'm2m': [],
 'childrens': [{'source_pk': 1603,
   'duplicate': True,
   'app_name': 'cmsmenus',
   'model_name': 'NavigationBarItem',
   'object': {'created_by': 2,
    'created_by_id': 2,
    'order': 1,
    'is_active': True,
    'name': 'child 1',
    'parent': 1602,
    'parent_id': 1602,
    'url': 'None'},
   'm2m': [],
   'childrens': [{'source_pk': 1604,
     'duplicate': True,
     'app_name': 'cmsmenus',
     'model_name': 'NavigationBarItem',
     'object': {'created_by': 2,
      'created_by_id': 2,
      'order': 2,
      'is_active': True,
      'menu': 266,
      'menu_id': 266,
      'name': 'child 2',
      'url': 'None'},
     'm2m': [],
     'childrens': [],
     'depth': 2,
     'save': False,
     'related_field': 'parent'}],
   'depth': 1,
   'save': False,
   'related_field': 'menu'},
  {'source_pk': 1604,
   'duplicate': True,
   'app_name': 'cmsmenus',
   'model_name': 'NavigationBarItem',
   'object': {'created_by': 2,
    'created_by_id': 2,
    'order': 2,
    'is_active': True,
    'name': 'child 2',
    'parent': 1603,
    'parent_id': 1603,
    'url': 'None'},
   'm2m': [],
   'childrens': [],
   'depth': 1,
   'save': False,
   'related_field': 'menu'},
  {'source_pk': 1602,
   'duplicate': True,
   'app_name': 'cmsmenus',
   'model_name': 'NavigationBarItem',
   'object': {'created_by': 2,
    'created_by_id': 2,
    'modified_by': 2,
    'modified_by_id': 2,
    'order': 10,
    'is_active': True,
    'name': 'parent',
    'url': 'None'},
   'm2m': [],
   'childrens': [{'source_pk': 1603,
     'duplicate': True,
     'app_name': 'cmsmenus',
     'model_name': 'NavigationBarItem',
     'object': {'created_by': 2,
      'created_by_id': 2,
      'order': 1,
      'is_active': True,
      'menu': 266,
      'menu_id': 266,
      'name': 'child 1',
      'url': 'None'},
     'm2m': [],
     'childrens': [{'source_pk': 1604,
       'duplicate': True,
       'app_name': 'cmsmenus',
       'model_name': 'NavigationBarItem',
       'object': {'created_by': 2,
        'created_by_id': 2,
        'order': 2,
        'is_active': True,
        'menu': 266,
        'menu_id': 266,
        'name': 'child 2',
        'url': 'None'},
       'm2m': [],
       'childrens': [],
       'depth': 3,
       'save': True,
       'related_field': 'parent'}],
     'depth': 2,
     'save': True,
     'related_field': 'parent'},
    {'source_pk': 35,
     'duplicate': True,
     'app_name': 'cmsmenus',
     'model_name': 'NavigationBarItemLocalization',
     'object': {'created_by': 2,
      'created_by_id': 2,
      'modified_by': 2,
      'modified_by_id': 2,
      'is_active': True,
      'language': 'en',
      'name': 'adasdasd'},
     'm2m': [],
     'childrens': [],
     'depth': 2,
     'save': True,
     'related_field': 'item'}],
   'depth': 1,
   'save': True,
   'related_field': 'menu'}],
 'depth': 0,
 'save': True}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-auto-serializer-0.4.2.tar.gz (12.9 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page