Skip to content

Instantly share code, notes, and snippets.

@skakri
Created April 3, 2014 06:44
Show Gist options
  • Save skakri/9949384 to your computer and use it in GitHub Desktop.
Save skakri/9949384 to your computer and use it in GitHub Desktop.
Python snippets
#
# Django
#
# better solution than model_to_dict, if you need model instance dict, which holds m2m field values
# source: https://djangosnippets.org/snippets/2278/ (gabipurcaru)
from types import NoneType
from django.db.models.manager import Manager
from django.db.models import Model
import datetime
def get_values(instance, go_into={}, exclude=(), extra=()):
"""
Transforms a django model instance into an object that can be used for
serialization. Also transforms datetimes into timestamps.
@param instance(django.db.models.Model) - the model in question
@param go_into(dict) - relations with other models that need expanding
@param exclude(tuple) - fields that will be ignored
@param extra(tuple) - additional functions/properties which are not fields
Usage:
get_values(MyModel.objects.get(pk=187),
{'user': {'go_into': ('clan',),
'exclude': ('crest_blob',),
'extra': ('get_crest_path',)}},
('image'))
"""
SIMPLE_TYPES = (int, long, str, list, dict, tuple, bool, float, bool,
unicode, NoneType)
if not isinstance(instance, Model):
raise TypeError("Argument is not a Model")
value = {
'pk': instance.pk,
}
# check for simple string instead of tuples
# and dicts; this is shorthand syntax
if isinstance(go_into, str):
go_into = {go_into: {}}
if isinstance(exclude, str):
exclude = (exclude,)
if isinstance(extra, str):
extra = (extra,)
# process the extra properties/function/whatever
for field in extra:
property = getattr(instance, field)
if callable(property):
property = property()
if isinstance(property, SIMPLE_TYPES):
value[field] = property
else:
value[field] = repr(property)
field_options = instance._meta.get_all_field_names()
for field in field_options:
try:
property = getattr(instance, field)
except:
continue
if field in exclude or field[0] == '_' or isinstance(property, Manager):
# if it's in the exclude tuple, ignore it
# if it's a "private" field, ignore it
# if it's an instance of manager (this means a more complicated
# relationship), ignore it
continue
elif go_into.has_key(field):
# if it's in the go_into dict, make a recursive call for that field
try:
field_go_into = go_into[field].get('go_into', {})
except AttributeError:
field_go_into = {}
try:
field_exclude = go_into[field].get('exclude', ())
except AttributeError:
field_exclude = ()
try:
field_extra = go_into[field].get('extra', ())
except AttributeError:
field_extra = ()
value[field] = get_values(property,
field_go_into,
field_exclude,
field_extra)
else:
if isinstance(property, Model):
# if it's a model, we need it's PK #
value[field] = property.pk
elif isinstance(property, (datetime.date,
datetime.time,
datetime.datetime)):
# if it's a date/time, we need it #
# in iso format for serialization #
value[field] = property.isoformat()
else:
# else, we just put the value #
if callable(property):
property = property()
if isinstance(property, SIMPLE_TYPES):
value[field] = property
else:
value[field] = repr(property)
return value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment