Extracted deserialize fk/m2m functions from Deserializer.
In preparation for handling forward references (refs #26291).
This commit is contained in:
parent
a0c03c62a8
commit
73f7d1755f
|
@ -28,6 +28,13 @@ class DeserializationError(Exception):
|
||||||
return cls("%s: (%s:pk=%s) field_value was '%s'" % (original_exc, model, fk, field_value))
|
return cls("%s: (%s:pk=%s) field_value was '%s'" % (original_exc, model, fk, field_value))
|
||||||
|
|
||||||
|
|
||||||
|
class M2MDeserializationError(Exception):
|
||||||
|
"""Something bad happened during deserialization of a ManyToManyField."""
|
||||||
|
def __init__(self, original_exc, pk):
|
||||||
|
self.original_exc = original_exc
|
||||||
|
self.pk = pk
|
||||||
|
|
||||||
|
|
||||||
class ProgressBar:
|
class ProgressBar:
|
||||||
progress_width = 75
|
progress_width = 75
|
||||||
|
|
||||||
|
@ -235,3 +242,42 @@ def build_instance(Model, data, db):
|
||||||
except Model.DoesNotExist:
|
except Model.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
def deserialize_m2m_values(field, field_value, using):
|
||||||
|
model = field.remote_field.model
|
||||||
|
if hasattr(model._default_manager, 'get_by_natural_key'):
|
||||||
|
def m2m_convert(value):
|
||||||
|
if hasattr(value, '__iter__') and not isinstance(value, str):
|
||||||
|
return model._default_manager.db_manager(using).get_by_natural_key(*value).pk
|
||||||
|
else:
|
||||||
|
return model._meta.pk.to_python(value)
|
||||||
|
else:
|
||||||
|
def m2m_convert(v):
|
||||||
|
return model._meta.pk.to_python(v)
|
||||||
|
|
||||||
|
try:
|
||||||
|
values = []
|
||||||
|
for pk in field_value:
|
||||||
|
values.append(m2m_convert(pk))
|
||||||
|
return values
|
||||||
|
except Exception as e:
|
||||||
|
raise M2MDeserializationError(e, pk)
|
||||||
|
|
||||||
|
|
||||||
|
def deserialize_fk_value(field, field_value, using):
|
||||||
|
if field_value is None:
|
||||||
|
return None
|
||||||
|
model = field.remote_field.model
|
||||||
|
default_manager = model._default_manager
|
||||||
|
field_name = field.remote_field.field_name
|
||||||
|
if (hasattr(default_manager, 'get_by_natural_key') and
|
||||||
|
hasattr(field_value, '__iter__') and not isinstance(field_value, str)):
|
||||||
|
obj = default_manager.db_manager(using).get_by_natural_key(*field_value)
|
||||||
|
value = getattr(obj, 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 model._meta.pk.remote_field:
|
||||||
|
value = value.pk
|
||||||
|
return value
|
||||||
|
return model._meta.get_field(field_name).to_python(field_value)
|
||||||
|
|
|
@ -117,49 +117,18 @@ def Deserializer(object_list, *, using=DEFAULT_DB_ALIAS, ignorenonexistent=False
|
||||||
|
|
||||||
# Handle M2M relations
|
# Handle M2M relations
|
||||||
if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
|
if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
|
||||||
model = field.remote_field.model
|
|
||||||
if hasattr(model._default_manager, 'get_by_natural_key'):
|
|
||||||
def m2m_convert(value):
|
|
||||||
if hasattr(value, '__iter__') and not isinstance(value, str):
|
|
||||||
return model._default_manager.db_manager(using).get_by_natural_key(*value).pk
|
|
||||||
else:
|
|
||||||
return model._meta.pk.to_python(value)
|
|
||||||
else:
|
|
||||||
def m2m_convert(v):
|
|
||||||
return model._meta.pk.to_python(v)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
m2m_data[field.name] = []
|
values = base.deserialize_m2m_values(field, field_value, using)
|
||||||
for pk in field_value:
|
except base.M2MDeserializationError as e:
|
||||||
m2m_data[field.name].append(m2m_convert(pk))
|
raise base.DeserializationError.WithData(e.original_exc, d['model'], d.get('pk'), e.pk)
|
||||||
except Exception as e:
|
m2m_data[field.name] = values
|
||||||
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), pk)
|
|
||||||
|
|
||||||
# Handle FK fields
|
# Handle FK fields
|
||||||
elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
|
elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
|
||||||
model = field.remote_field.model
|
|
||||||
if field_value is not None:
|
|
||||||
try:
|
try:
|
||||||
default_manager = model._default_manager
|
value = base.deserialize_fk_value(field, field_value, using)
|
||||||
field_name = field.remote_field.field_name
|
|
||||||
if hasattr(default_manager, 'get_by_natural_key'):
|
|
||||||
if hasattr(field_value, '__iter__') and not isinstance(field_value, str):
|
|
||||||
obj = default_manager.db_manager(using).get_by_natural_key(*field_value)
|
|
||||||
value = getattr(obj, field.remote_field.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 model._meta.pk.remote_field:
|
|
||||||
value = value.pk
|
|
||||||
else:
|
|
||||||
value = model._meta.get_field(field_name).to_python(field_value)
|
|
||||||
data[field.attname] = value
|
|
||||||
else:
|
|
||||||
data[field.attname] = model._meta.get_field(field_name).to_python(field_value)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
|
raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
|
||||||
else:
|
data[field.attname] = value
|
||||||
data[field.attname] = None
|
|
||||||
|
|
||||||
# Handle all other fields
|
# Handle all other fields
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in New Issue