Last active
March 28, 2024 15:35
-
-
Save haginara/5f4288670fec5e58cd1d1085f9e2b17e to your computer and use it in GitHub Desktop.
Custom model_to_dict.py that supports ManyToOne Fields
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import chain | |
def model_to_dict(instance, fields=None, exclude=None): | |
""" | |
Returns a dict containing the data in ``instance`` suitable for passing as | |
a Form's ``initial`` keyword argument. | |
``fields`` is an optional list of field names. If provided, only the named | |
fields will be included in the returned dict. | |
``exclude`` is an optional list of field names. If provided, the named | |
fields will be excluded from the returned dict, even if they are listed in | |
the ``fields`` argument. | |
""" | |
# avoid a circular import | |
from django.db.models.fields.related import ManyToManyField, ManyToOneRel | |
opts = instance._meta | |
data = {} | |
for f in chain(opts.concrete_fields, opts.virtual_fields, opts.many_to_many, opts.get_all_related_objects()): | |
if not getattr(f, 'editable', False) and not isinstance(f, ManyToOneRel): | |
continue | |
if fields and f.name not in fields: | |
continue | |
if exclude and f.name in exclude: | |
continue | |
if isinstance(f, ManyToManyField): | |
# If the object doesn't have a primary key yet, just use an empty | |
# list for its m2m fields. Calling f.value_from_object will raise | |
# an exception. | |
if instance.pk is None: | |
data[f.name] = [] | |
else: | |
# MultipleChoiceWidget needs a list of pks, not object instances. | |
qs = f.value_from_object(instance) | |
if qs._result_cache is not None: | |
data[f.name] = [item.pk for item in qs] | |
else: | |
data[f.name] = list(qs.values_list('pk', flat=True)) | |
elif isinstance(f, ManyToOneRel): | |
data[f.name] = getattr(instance, f.get_accessor_name()).all() | |
else: | |
data[f.name] = f.value_from_object(instance) | |
return data |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This doesn't work in the newest version of django, I applied a fix and it works
qs._result_cache is not an attribtue of QuerySet anymore so I removed the check, also its now somewhat recursive so I added a check so it dosnt end up in an infinite loop crashing the application.