diff -r b758351d191f -r cc9b7e14412b web/lib/django/core/serializers/python.py --- 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