2015-03-09

Xmldump: Dumping Django data state to XML

The problem: Migrating Django model data across model versions

I've been working on learning Django. There's probably a better way of doing this that I don't know about, but as near as I can tell there is no way to back up the state of the db in any way that can migrate across versions. There is

There is a stack overflow question on the topic here. It is an old question, with a few third party solutions. A more recent answer references new Django support for migrations. However, migrations requires that you write significant code for non-trivial changes.

I wanted a solution that would let my classes load themselves from older representations. Preferably automatically, but with the option of custom code for non-trivial cases. I searched around a while and could not find anything, so I wrote it myself.

XMLDump

An example project that illustrates using xmldump is here. The only file you need to use it yourself is serializable.py which defines a mixin. Include it as a base class for any models that you want to be able to dump to xml. The file also includes documentation on how to use it, which I've include that below.


The serializable module can save django data to xml format and
reimport. The intent is that in most cases no customization should
be required. However, I expect that there are still many cases where
the code is not yet able to handle the model relationships.
For instance, I have made no particular effort to implement many to
many relationships.
To generate xml from the models currently in memory:
      import serializable
      xml = serializable.models_to_xml([TopLevelModelClass1, Class2])

The xml that is returned is an instance of the xml.etree.ElmentTree.Element
class. To display it in a readable format:
      from xml.dom.minidom import parseString
      doc = parseString( xml.etree.ElmentTree.tostring(xml) )
      xml_string = doc.toprettyxml('  ')

In order to delete all the data in memory (in preparation for reloading it,
presumably):
      delete_all_models_in_db([TopLevelModelClass1, Class2])

The list of class names that must be passed to the functions need not
contain all the model classes. They should contain the highest level
classes only. The module will discover contained classes, whether they
be models which are referred to by a foreign key, or models which refer
to the high level model class through a foreign key.
However, it may be advisable to overload the "owned_models" function
in order to restrict the default discovery. In some cases it makes
for a nicer xml nesting if references are not followed all the way
down.

Example output

<?xml version="1.0" ?>
<ModelData>
  <xmldump.models.Menu>
    <id type="int">1</id>
    <name type="unicode">Breakfast</name>
    <___owned>
      <xmldump.models.MenuItem>
        <menu to_type="xmldump.models.Menu" type="reference">1</menu>
        <price type="float">4.0</price>
        <id type="int">1</id>
        <name type="unicode">Spam and Eggs</name>
      </xmldump.models.MenuItem>
      <xmldump.models.MenuItem>
        <menu to_type="xmldump.models.Menu" type="reference">1</menu>
        <price type="float">4.5</price>
        <id type="int">2</id>
        <name type="unicode">Eggs and Spam</name>
      </xmldump.models.MenuItem>
      <xmldump.models.MenuItem>
        <menu to_type="xmldump.models.Menu" type="reference">1</menu>
        <price type="float">5.0</price>
        <id type="int">3</id>
        <name type="unicode">Spammity Spam</name>
      </xmldump.models.MenuItem>
      <xmldump.models.MenuItem>
        <menu to_type="xmldump.models.Menu" type="reference">1</menu>
        <price type="float">3.0</price>
        <id type="int">4</id>
        <name type="unicode">Spam</name>
      </xmldump.models.MenuItem>
    </___owned>
  </xmldump.models.Menu>
  <xmldump.models.Order>
    <customer type="unicode">Brian</customer>
    <date type="date">2015-03-04</date>
    <id type="int">1</id>
    <___owned>
      <xmldump.models.OrderEntry>
        <order to_type="xmldump.models.Order" type="reference">1</order>
        <count type="int">1</count>
        <menuitem to_type="xmldump.models.MenuItem" type="reference">1</menuitem>
        <id type="int">1</id>
      </xmldump.models.OrderEntry>
      <xmldump.models.OrderEntry>
        <order to_type="xmldump.models.Order" type="reference">1</order>
        <count type="int">1</count>
        <menuitem to_type="xmldump.models.MenuItem" type="reference">2</menuitem>
        <id type="int">2</id>
      </xmldump.models.OrderEntry>
      <xmldump.models.OrderEntry>
        <order to_type="xmldump.models.Order" type="reference">1</order>
        <count type="int">2</count>
        <menuitem to_type="xmldump.models.MenuItem" type="reference">4</menuitem>
        <id type="int">3</id>
      </xmldump.models.OrderEntry>
    </___owned>
  </xmldump.models.Order>
</ModelData>


(Thanks to Free Online XML Escape Tool - freeformatter.com.)

No comments:

Post a Comment