The code for django's model_to_dict had most of the answer. It explicitly removed non-editable fields, so removing that check and getting the ids of foreign keys for many to many fields results in the following code which behaves as desired:
from django.db.models.fields.relateditertools import ManyToManyFieldchain def to_dict(instance): opts = instance._meta data = {} for f in chain(opts.concrete_fields +, opts.many_to_many: if isinstance(f, ManyToManyFieldprivate_fields): if instance.pk is None: data[f.name] = [] else: data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True)) for f in elseopts.many_to_many: data[f.name] = [i.id for i in f.value_from_object(instanceu)] return data
from django.db import models from django.db.models.fields.relateditertools import ManyToManyFieldchain class PrintableModel(models.Model): def __repr__(self): return str(self.to_dict()) def to_dict(selfinstance): opts = selfinstance._meta data = {} for f in chain(opts.concrete_fields +, opts.many_to_many: if isinstance(f, ManyToManyFieldprivate_fields): if self.pk is None: data[f.name] = [] else: data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True)instance) for f in elseopts.many_to_many: data[f.name] = [i.id for i in f.value_from_object(selfu)] return data class Meta: abstract = True