web/lib/django/core/serializers/python.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
--- a/web/lib/django/core/serializers/python.py	Wed May 19 17:43:59 2010 +0200
+++ b/web/lib/django/core/serializers/python.py	Tue May 25 02:43:45 2010 +0200
@@ -6,7 +6,7 @@
 
 from django.conf import settings
 from django.core.serializers import base
-from django.db import models
+from django.db import models, DEFAULT_DB_ALIAS
 from django.utils.encoding import smart_unicode, is_protected_type
 
 class Serializer(base.Serializer):
@@ -47,17 +47,24 @@
     def handle_fk_field(self, obj, field):
         related = getattr(obj, field.name)
         if related is not None:
-            if field.rel.field_name == related._meta.pk.name:
-                # Related to remote object via primary key
-                related = related._get_pk_val()
+            if self.use_natural_keys and hasattr(related, 'natural_key'):
+                related = related.natural_key()
             else:
-                # Related to remote object via other field
-                related = getattr(related, field.rel.field_name)
-        self._current[field.name] = smart_unicode(related, strings_only=True)
+                if field.rel.field_name == related._meta.pk.name:
+                    # Related to remote object via primary key
+                    related = related._get_pk_val()
+                else:
+                    # Related to remote object via other field
+                    related = smart_unicode(getattr(related, field.rel.field_name), strings_only=True)
+        self._current[field.name] = related
 
     def handle_m2m_field(self, obj, field):
-        if field.creates_table:
-            self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
+        if field.rel.through._meta.auto_created:
+            if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
+                m2m_value = lambda value: value.natural_key()
+            else:
+                m2m_value = lambda value: smart_unicode(value._get_pk_val(), strings_only=True)
+            self._current[field.name] = [m2m_value(related)
                                for related in getattr(obj, field.name).iterator()]
 
     def getvalue(self):
@@ -70,6 +77,7 @@
     It's expected that you pass the Python objects themselves (instead of a
     stream or a string) to the constructor
     """
+    db = options.pop('using', DEFAULT_DB_ALIAS)
     models.get_apps()
     for d in object_list:
         # Look up the model and starting build a dict of data for it.
@@ -86,13 +94,32 @@
 
             # Handle M2M relations
             if field.rel and isinstance(field.rel, models.ManyToManyRel):
-                m2m_convert = field.rel.to._meta.pk.to_python
-                m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
+                if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
+                    def m2m_convert(value):
+                        if hasattr(value, '__iter__'):
+                            return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
+                        else:
+                            return smart_unicode(field.rel.to._meta.pk.to_python(value))
+                else:
+                    m2m_convert = lambda v: smart_unicode(field.rel.to._meta.pk.to_python(v))
+                m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
 
             # Handle FK fields
             elif field.rel and isinstance(field.rel, models.ManyToOneRel):
                 if field_value is not None:
-                    data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                    if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
+                        if hasattr(field_value, '__iter__'):
+                            obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
+                            value = getattr(obj, field.rel.field_name)
+                            # If this is a natural foreign key to an object that
+                            # has a FK/O2O as the foreign key, use the FK value
+                            if field.rel.to._meta.pk.rel:
+                                value = value.pk
+                        else:
+                            value = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                        data[field.attname] = value
+                    else:
+                        data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
                 else:
                     data[field.attname] = None