Converta o objeto Django Model em ditado com todos os campos intactos

258

Como se converte um objeto Django Model em um ditado com todos os seus campos? Tudo idealmente inclui chaves estrangeiras e campos comeditable=False .

Deixe-me elaborar. Digamos que eu tenho um modelo Django como o seguinte:

from django.db import models

class OtherModel(models.Model): pass

class SomeModel(models.Model):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

No terminal, fiz o seguinte:

other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()

Quero converter isso no seguinte dicionário:

{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
 'foreign_key': 1,
 'id': 1,
 'many_to_many': [1],
 'normal_value': 1,
 'readonly_value': 2}

Perguntas com respostas insatisfatórias:

Django: Convertendo um conjunto inteiro de objetos de um modelo em um único dicionário

Como transformar objetos do Django Model em um dicionário e ainda ter suas chaves estrangeiras?

Zags
fonte
1
você pode declarar um método chamado to_dicte manipulá-lo da maneira que desejar.
precisa saber é o seguinte
@karthikr sim, eu poderia. A questão é como criar esse método. Construir manualmente um dicionário a partir de todos os campos do modelo não é uma resposta adequada.
Zags
Eu utilizaria uma biblioteca ReST existente como Django Rest Framework, Tastypie ou Piston, pois todas elas fornecem mecanismos para converter instâncias do modelo django em primitivas para serialização. Se você tiver mais curiosidade de como, pode ver o código deles, mas é principalmente percorrer as _metadefinições do modelo para encontrar os campos associados ao modelo e recuperar seus valores na instância.
Kevin Pedra

Respostas:

526

Existem várias maneiras de converter uma instância em um dicionário, com graus variados de manipulação de casos de canto e proximidade com o resultado desejado.


1 instance.__dict__

instance.__dict__

que retorna

{'_foreign_key_cache': <OtherModel: OtherModel object>,
 '_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
 'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

Essa é de longe a mais simples, mas está faltando many_to_many, foreign_keyestá com o nome errado e tem duas coisas extras indesejadas.


2) model_to_dict

from django.forms.models import model_to_dict
model_to_dict(instance)

que retorna

{'foreign_key': 2,
 'id': 1,
 'many_to_many': [<OtherModel: OtherModel object>],
 'normal_value': 1}

Este é o único com many_to_many, mas faltam os campos não editáveis.


3) model_to_dict(..., fields=...)

from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])

que retorna

{'foreign_key': 2, 'id': 1, 'normal_value': 1}

Isso é estritamente pior que a model_to_dictinvocação padrão .


4) query_set.values()

SomeModel.objects.filter(id=instance.id).values()[0]

que retorna

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

É a mesma saída, instance.__dict__mas sem os campos extras. foreign_key_idainda está errado e many_to_manyainda está faltando.


5. Função Personalizada

O código para django's model_to_dictteve a maior parte da resposta. Ele removeu explicitamente os campos não editáveis, portanto, remover essa verificação e obter os IDs de chaves estrangeiras de muitos a muitos campos resulta no seguinte código, que se comporta conforme o desejado:

from itertools import chain

def to_dict(instance):
    opts = instance._meta
    data = {}
    for f in chain(opts.concrete_fields, opts.private_fields):
        data[f.name] = f.value_from_object(instance)
    for f in opts.many_to_many:
        data[f.name] = [i.id for i in f.value_from_object(instance)]
    return data

Embora essa seja a opção mais complicada, a chamada to_dict(instance)nos dá exatamente o resultado desejado:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

6. Use serializadores

O ModelSerialzer do Django Rest Framework permite criar um serializador automaticamente a partir de um modelo.

from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SomeModel
        fields = "__all__"

SomeModelSerializer(instance).data

retorna

{'auto_now_add': '2018-12-20T21:34:29.494827Z',
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

Isso é quase tão bom quanto a função personalizada, mas auto_now_add é uma sequência em vez de um objeto datetime.


Rodada de bônus: melhor impressão do modelo

Se você deseja um modelo de django que tenha uma melhor exibição da linha de comando python, faça com que seus modelos sejam da classe filho da seguinte maneira:

from django.db import models
from itertools import chain

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(instance):
        opts = instance._meta
        data = {}
        for f in chain(opts.concrete_fields, opts.private_fields):
            data[f.name] = f.value_from_object(instance)
        for f in opts.many_to_many:
            data[f.name] = [i.id for i in f.value_from_object(instance)]
        return data

    class Meta:
        abstract = True

Então, por exemplo, se definirmos nossos modelos como tal:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

A chamada SomeModel.objects.first()agora produz resultados como este:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}
Zags
fonte
2
Obrigado por esta resposta! Você pode alterar o isinstanceteste na solução 5 (e o bônus) para if f.many_to_many.
dhobbs
1
@dhobbs Eu modelei esse código do código do Django model_to_dict, que usa isinstance. Eu não sei por que eles fizeram essa escolha, mas pode haver uma boa razão para isso (como a many_to_manypropriedade que está sendo introduzido em uma versão posterior)
Zags
também retornaria @propertycampos?
Angrysumit 8/1018
1
Gostaria de saber como esses métodos tratariam os campos anotados / agregados?
quer
Algo que faço é procurar por get_FOO_display e retornar esse valor em vez de qualquer valor que possa realmente estar lá.
Bobort
9

Encontrei uma solução interessante para obter o resultado:

Suponha que você tenha um objeto de modelo o :

Apenas ligue:

type(o).objects.filter(pk=o.pk).values().first()
Alfred Huang
fonte
10
Este é apenas opção # 4 na minha resposta
Zags
7

A solução @Zags foi maravilhosa!

Eu acrescentaria, no entanto, uma condição para os campos de data para torná-lo compatível com JSON.

Rodada de Bônus

Se você deseja um modelo django que tenha uma melhor exibição da linha de comando python, faça com que seus modelos filhem a seguinte classe:

from django.db import models
from django.db.models.fields.related import ManyToManyField

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self):
        opts = self._meta
        data = {}
        for f in opts.concrete_fields + opts.many_to_many:
            if isinstance(f, ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True))
            elif isinstance(f, DateTimeField):
                if f.value_from_object(self) is not None:
                    data[f.name] = f.value_from_object(self).timestamp()
            else:
                data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)
        return data

    class Meta:
        abstract = True

Então, por exemplo, se definirmos nossos modelos como tal:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    value = models.IntegerField()
    value2 = models.IntegerField(editable=False)
    created = models.DateTimeField(auto_now_add=True)
    reference1 = models.ForeignKey(OtherModel, related_name="ref1")
    reference2 = models.ManyToManyField(OtherModel, related_name="ref2")

A chamada SomeModel.objects.first()agora produz resultados como este:

{'created': 1426552454.926738,
'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]}
Diego Freitas Coelho
fonte
Se você deseja converter de e para JSON, deve procurar no Django Rest Framework ou usar algo como isto: stackoverflow.com/a/22238613/2800876
Zags
Certo! Mas essa pequena alteração no seu código adiciona muita conveniência!
Diego Freitas Coelho
4

Maneira mais simples,

  1. Se sua consulta for Model.Objects.get ():

    get () retornará uma instância única para que você possa usar diretamente __dict__ da sua instância

    model_dict = Model.Objects.get().__dict__

  2. para filter () / all ():

    all () / filter () retornará uma lista de instâncias para que você possa usarvalues() para obter a lista de objetos.

    model_values ​​= Model.Objects.all (). values ​​()

Mohideen bin Mohammed
fonte
4

apenas vars(obj), indicará todos os valores do objeto

>>> obj_attrs = vars(obj)
>>> obj_attrs
 {'_file_data_cache': <FileData: Data>,
  '_state': <django.db.models.base.ModelState at 0x7f5c6733bad0>,
  'aggregator_id': 24,
  'amount': 5.0,
  'biller_id': 23,
  'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
  'file_data_id': 797719,
 }

Você pode adicionar isso também

>>> keys = obj_attrs.keys()
>>> temp = [obj_attrs.pop(key) if key.startswith('_') else None for key in keys]
>>> del temp
>>> obj_attrs
   {
    'aggregator_id': 24,
    'amount': 5.0,
    'biller_id': 23,
    'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
    'file_data_id': 797719,
   }
A.Raouf
fonte
3

Atualizar

A resposta agregada mais recente publicada por @zags é mais completa e elegante que a minha. Por favor, consulte essa resposta.

Original

Se você estiver disposto a definir seu próprio método to_dict como o @karthiker sugeriu, isso resume o problema a um problema de conjuntos.

>>># Returns a set of all keys excluding editable = False keys
>>>dict = model_to_dict(instance)
>>>dict

{u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1}


>>># Returns a set of editable = False keys, misnamed foreign keys, and normal keys
>>>otherDict = SomeModel.objects.filter(id=instance.id).values()[0]
>>>otherDict

{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1_id': 1L,
 'value': 1L,
 'value2': 2L}

Precisamos remover as chaves estrangeiras rotuladas incorretamente de otherDict .

Para fazer isso, podemos usar um loop que cria um novo dicionário que possui todos os itens, exceto aqueles com sublinhados. Ou, para economizar tempo, podemos apenas adicioná-los ao ditado original, pois os dicionários são apenas conjuntos escondidos.

>>>for item in otherDict.items():
...    if "_" not in item[0]:
...            dict.update({item[0]:item[1]})
...
>>>

Assim, ficamos com o seguinte ditado :

>>>dict
{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1': 1L,
 'reference2': [1L],
 'value': 1,
 'value2': 2L}

E você acabou de devolver isso.

No lado negativo, você não pode usar sublinhados em seus nomes de campo editáveis ​​= falsos. No lado positivo, isso funcionará para qualquer conjunto de campos em que os campos criados pelo usuário não contenham sublinhados.

Essa não é a melhor maneira de fazer isso, mas pode funcionar como uma solução temporária até que um método mais direto seja encontrado.

Para o exemplo abaixo, dict seria formado com base em model_to_dict e otherDict seria formado pelo método de valores do filtro. Eu teria feito isso com os próprios modelos, mas não consigo fazer com que minha máquina aceite outroModelo.

>>> import datetime
>>> dict = {u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1}
>>> otherDict = {'created': datetime.datetime(2014, 2, 21, 4, 38, 51), u'id': 1, 'reference1_id': 1, 'value': 1, 'value2': 2}
>>> for item in otherDict.items():
...     if "_" not in item[0]:
...             dict.update({item[0]:item[1]})
...
>>> dict
{'reference1': 1, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51), 'value2': 2, 'value': 1, 'id': 1, 'reference2': [1]}
>>>

Isso deve colocá-lo em uma estimativa aproximada da resposta à sua pergunta, espero.

Gadget
fonte
1
Não tenho certeza do que você está tentando usar reaqui. Se é para filtrar as chaves com sublinhados, isso não é um código correto nem um comportamento correto. re.match("_", "reference1_id")retornos Nonee colunas legítimas no banco de dados podem ter sublinhados em seus nomes.
Zags
re.match ("_", "reference1_id") retorna None, deveria ter sido: re.match (". * _. *", "reference1_id")
Gadget
Fiz algumas alterações para remover o exemplo ruim e incluir um melhor. Também mudei algumas coisas para expressar que essa seria uma solução temporária para um subconjunto de todos os modelos. Não tenho idéia do que você faria para modelos com sublinhados em seus editable=falsecampos. Eu só estava tentando fornecer algo com o qual você possa trabalhar até que uma solução mais cânone possa ser fornecida.
Gadget
Talvez use "_" in stringmais do que renesse caso.
Zags
Sim, seria uma maneira muito mais fácil de fazer isso. Não me ocorreu usá-lo dessa maneira, mas agora faz muito sentido. Eu mudei a resposta para usar em invez de re.
Gadget
2

Muitas soluções interessantes aqui. Minha solução foi adicionar um método as_dict ao meu modelo com uma compreensão de dict.

def as_dict(self):
    return dict((f.name, getattr(self, f.name)) for f in self._meta.fields)

Como um bônus, esta solução combinada com uma compreensão da lista em uma consulta é uma boa solução se você deseja exportar seus modelos para outra biblioteca. Por exemplo, despejando seus modelos em um dataframe do pandas:

pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()])
t1m0
fonte
1
Esta multa funciona para campos de valor, como cordas e ints, mas terá alguns problemas com chaves estrangeiras e ainda mais com muitos para muitos campos
Zags
Muito bom ponto! Especialmente para muitos para muitos. Alguém gostaria de colocar alguns condicionais para lidar com esses casos adequadamente ou limitar essa solução a modelos simples. Obrigado.
t1m0
1

(não quis fazer o comentário)

Ok, isso realmente não depende de tipos dessa maneira. Eu posso ter entendido errado a pergunta original aqui, então me perdoe se for esse o caso. Se você criar o serliazers.py, criará classes que possuem meta classes.

Class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = modelName
        fields =('csv','of','fields')

Então, quando você obtém os dados na classe view, pode:

model_data - Model.objects.filter(...)
serializer = MyModelSerializer(model_data, many=True)
return Response({'data': serilaizer.data}, status=status.HTTP_200_OK)

Isso é praticamente o que eu tenho em vários locais e retorna JSON agradável por meio do JSONRenderer.

Como eu disse, isso é cortesia do DjangoRestFramework, então vale a pena investigar isso.

nathj07
fonte
1

A maneira mais fácil é usar apenas pprint, que está no Python base

import pprint
item = MyDjangoModel.objects.get(name = 'foo')
pprint.pprint(item.__dict__, indent = 4)

Isso fornece uma saída semelhante, json.dumps(..., indent = 4)mas lida corretamente com os tipos de dados estranhos que podem ser incorporados à instância do modelo, como ModelStateeUUID , etc.

Testado em Python 3.7

user5359531
fonte
0

Talvez isso ajude você. Que isso não oculte muitos ou muitos relacionamentos, mas é bastante útil quando você deseja enviar seu modelo em formato json.

def serial_model(modelobj):
  opts = modelobj._meta.fields
  modeldict = model_to_dict(modelobj)
  for m in opts:
    if m.is_relation:
        foreignkey = getattr(modelobj, m.name)
        if foreignkey:
            try:
                modeldict[m.name] = serial_model(foreignkey)
            except:
                pass
  return modeldict
Pjl
fonte
0

A melhor solução que você já viu.

Converta a instância django.db.models.Model e todos os campos de função ForeignKey, ManyToManyField e @Property relacionados em dict.

"""
Convert django.db.models.Model instance and all related ForeignKey, ManyToManyField and @property function fields into dict.
Usage:
    class MyDjangoModel(... PrintableModel):
        to_dict_fields = (...)
        to_dict_exclude = (...)
        ...
    a_dict = [inst.to_dict(fields=..., exclude=...) for inst in MyDjangoModel.objects.all()]
"""
import typing

import django.core.exceptions
import django.db.models
import django.forms.models


def get_decorators_dir(cls, exclude: typing.Optional[set]=None) -> set:
    """
    Ref: /programming/4930414/how-can-i-introspect-properties-and-model-fields-in-django
    :param exclude: set or None
    :param cls:
    :return: a set of decorators
    """
    default_exclude = {"pk", "objects"}
    if not exclude:
        exclude = default_exclude
    else:
        exclude = exclude.union(default_exclude)

    return set([name for name in dir(cls) if name not in exclude and isinstance(getattr(cls, name), property)])


class PrintableModel(django.db.models.Model):

    class Meta:
        abstract = True

    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self, fields: typing.Optional[typing.Iterable]=None, exclude: typing.Optional[typing.Iterable]=None):
        opts = self._meta
        data = {}

        # support fields filters and excludes
        if not fields:
            fields = set()
        else:
            fields = set(fields)
        default_fields = getattr(self, "to_dict_fields", set())
        fields = fields.union(default_fields)

        if not exclude:
            exclude = set()
        else:
            exclude = set(exclude)
        default_exclude = getattr(self, "to_dict_exclude", set())
        exclude = exclude.union(default_exclude)

        # support syntax "field__childField__..."
        self_fields = set()
        child_fields = dict()
        if fields:
            for i in fields:
                splits = i.split("__")
                if len(splits) == 1:
                    self_fields.add(splits[0])
                else:
                    self_fields.add(splits[0])

                    field_name = splits[0]
                    child_fields.setdefault(field_name, set())
                    child_fields[field_name].add("__".join(splits[1:]))

        self_exclude = set()
        child_exclude = dict()
        if exclude:
            for i in exclude:
                splits = i.split("__")
                if len(splits) == 1:
                    self_exclude.add(splits[0])
                else:
                    field_name = splits[0]
                    if field_name not in child_exclude:
                        child_exclude[field_name] = set()
                    child_exclude[field_name].add("__".join(splits[1:]))

        for f in opts.concrete_fields + opts.many_to_many:
            if self_fields and f.name not in self_fields:
                continue
            if self_exclude and f.name in self_exclude:
                continue

            if isinstance(f, django.db.models.ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    result = []
                    m2m_inst = f.value_from_object(self)
                    for obj in m2m_inst:
                        if isinstance(PrintableModel, obj) and hasattr(obj, "to_dict"):
                            d = obj.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )
                        else:
                            d = django.forms.models.model_to_dict(
                                obj,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        result.append(d)
                    data[f.name] = result
            elif isinstance(f, django.db.models.ForeignKey):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = None
                    try:
                        foreign_inst = getattr(self, f.name)
                    except django.core.exceptions.ObjectDoesNotExist:
                        pass
                    else:
                        if isinstance(foreign_inst, PrintableModel) and hasattr(foreign_inst, "to_dict"):
                            data[f.name] = foreign_inst.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        elif foreign_inst is not None:
                            data[f.name] = django.forms.models.model_to_dict(
                                foreign_inst,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )

            elif isinstance(f, (django.db.models.DateTimeField, django.db.models.DateField)):
                v = f.value_from_object(self)
                if v is not None:
                    data[f.name] = v.isoformat()
                else:
                    data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)

        # support @property decorator functions
        decorator_names = get_decorators_dir(self.__class__)
        for name in decorator_names:
            if self_fields and name not in self_fields:
                continue
            if self_exclude and name in self_exclude:
                continue

            value = getattr(self, name)
            if isinstance(value, PrintableModel) and hasattr(value, "to_dict"):
                data[name] = value.to_dict(
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name)
                )
            elif hasattr(value, "_meta"):
                # make sure it is a instance of django.db.models.fields.Field
                data[name] = django.forms.models.model_to_dict(
                    value,
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name),
                )
            elif isinstance(value, (set, )):
                data[name] = list(value)
            else:
                data[name] = value

        return data

https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52

Tony
fonte
0

A resposta do @zags é abrangente e deve ser suficiente, mas o método nº 5 (que é o melhor IMO) gera um erro, por isso aprimorei a função auxiliar.

Como o OP solicitou a conversão de many_to_manycampos em uma lista de chaves primárias, e não em uma lista de objetos, aprimorei a função para que o valor de retorno agora seja JSON serializável - convertendo datetimeobjetos em stre many_to_manyobjetos em uma lista de IDs.

import datetime

def ModelToDict(instance):
    '''
    Returns a dictionary object containing complete field-value pairs of the given instance

    Convertion rules:

        datetime.date --> str
        many_to_many --> list of id's

    '''

    concrete_fields = instance._meta.concrete_fields
    m2m_fields = instance._meta.many_to_many
    data = {}

    for field in concrete_fields:
        key = field.name
        value = field.value_from_object(instance)
        if type(value) == datetime.datetime:
            value = str(field.value_from_object(instance))
        data[key] = value

    for field in m2m_fields:
        key = field.name
        value = field.value_from_object(instance)
        data[key] = [rel.id for rel in value]

    return data
Armin Hemati Nik
fonte
Qual é o erro que você recebe? Estou feliz para atualizar a resposta
Zags
Atualmente, a funcionalidade dos loops concrete_fieldse m2m_fieldsparece idêntica, assumindo que o m2m_fieldsloop tenha uma implementação incorreta aqui.
Daniel Himmelstein
@ Zags o erro é AttributeError: 'list' object has no attribute 'values_list' que não consegui encontrar a razão por trás disso. Estou usando o Django 2.1.1
Armin Hemati Nik
@ daniel-himmelstein obrigado por apontar, eu corrigi o código. o motivo de loops idênticos ocorreu devido à realização de operações diferentes no meu código local e esqueci de otimizá-lo para a resposta SO.
Armin Hemati Nik
O @ArminHemati Django mudou a implementação field.value_from_objecte, como resultado, de model_to_dict. Atualizei a seção 5 da minha resposta para refletir isso.
Zags