Как преобразовать объект модели Django в dict со всеми его полями? Все в идеале включает в себя внешние ключи и поля с editable=False
.
Позвольте мне уточнить. Допустим, у меня есть модель Django, подобная следующей:
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")
В терминале я сделал следующее:
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()
Я хочу преобразовать это в следующий словарь:
{'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}
Вопросы с неудовлетворительными ответами:
Django: преобразование всего набора объектов модели в один словарь
Как я могу превратить объекты Django Model в словарь и сохранить их внешние ключи?
to_dict
и обрабатывать его так, как хотите._meta
определениям модели, чтобы найти поля, связанные с моделью, и получить их значения в экземпляре.Ответы:
Есть много способов преобразовать экземпляр в словарь, с различной степенью обработки угловых случаев и приближением к желаемому результату.
1.
instance.__dict__
который возвращается
Это, безусловно, самый простой, но отсутствует
many_to_many
,foreign_key
его неправильно называют, и в нем есть две нежелательные дополнительные вещи.2.
model_to_dict
который возвращается
Это единственный с
many_to_many
, но отсутствует недоступные для редактирования поля.3.
model_to_dict(..., fields=...)
который возвращается
Это строго хуже, чем стандартный
model_to_dict
вызов.4.
query_set.values()
который возвращается
Это тот же вывод, что и
instance.__dict__
без дополнительных полей.foreign_key_id
все еще не прав иmany_to_many
все еще отсутствует.5. Пользовательская функция
Код для Django
model_to_dict
имел большую часть ответа. Он явно удалил нередактируемые поля, поэтому удаление этой проверки и получение идентификаторов внешних ключей для многих и многих полей приводит к следующему коду, который ведет себя как нужно:Хотя это самый сложный вариант, вызов
to_dict(instance)
дает нам точно желаемый результат:6. Используйте Сериализаторы
ModelSerialzer в Django Rest Framework позволяет автоматически создавать сериализатор из модели.
возвращается
Это почти так же хорошо, как пользовательская функция, но auto_now_add - это строка вместо объекта datetime.
Бонус раунд: лучшая модель печати
Если вам нужна модель django с лучшим отображением командной строки на python, сделайте ваши модели дочерними по классу следующими:
Так, например, если мы определим наши модели как таковые:
Вызов
SomeModel.objects.first()
теперь дает вывод, как это:источник
isinstance
тест в решении № 5 (и бонус) наif f.many_to_many
.model_to_dict
кода Джанго , который используетisinstance
. Я не уверен, почему они сделали этот выбор, но для этого может быть веская причина (например,many_to_many
свойство, появившееся в более поздней версии)@property
поля?Я нашел аккуратное решение, чтобы получить результат:
Предположим, у вас есть модельный объект
o
:Просто позвони:
источник
Решение @Zags было великолепным!
Я бы добавил, однако, условие для полей даты, чтобы сделать его дружественным к JSON.
Бонус Раунд
Если вы хотите модель django с лучшим отображением командной строки на python, сделайте так, чтобы ваш дочерний класс моделей был следующим:
Так, например, если мы определим наши модели как таковые:
Вызов
SomeModel.objects.first()
теперь дает вывод, как это:источник
Самый простой способ,
Если ваш запрос - Model.Objects.get ():
получить () возвращает один экземпляр , так что вы можете направить использование
__dict__
от экземпляраmodel_dict =
Model.Objects.get().__dict__
для фильтра () / все ():
all () / filter () вернет список экземпляров, чтобы вы могли использовать их
values()
для получения списка объектов.model_values = Model.Objects.all (). values ()
источник
просто
vars(obj)
он будет указывать все значения объектаВы можете добавить это также
источник
Обновить
Новый обобщенный ответ, опубликованный @zags, является более полным и элегантным, чем мой собственный. Пожалуйста, обратитесь к этому ответу вместо.
оригинал
Если вы хотите определить свой собственный метод to_dict, как предложил @karthiker, то это сводит эту проблему к задаче множеств.
Нам нужно удалить ошибочно помеченные внешние ключи из otherDict .
Для этого мы можем использовать цикл, который создает новый словарь, в котором есть все элементы, кроме тех, в которых есть подчеркивания. Или, чтобы сэкономить время, мы можем просто добавить их в исходный текст, так как словари просто находятся под капотом.
Таким образом , мы остались со следующим Dict :
И вы просто верните это.
С другой стороны, вы не можете использовать подчеркивания в ваших редактируемых = ложных имен полей. С другой стороны, это будет работать для любого набора полей, где пользовательские поля не содержат подчеркивания.
Это не лучший способ сделать это, но он может работать как временное решение, пока не будет найден более прямой метод.
Для примера ниже, dict будет сформирован на основе model_to_dict, а otherDict будет сформирован методом значений фильтра. Я бы сделал это с самими моделями, но я не могу заставить свою машину принять другую модель.
Это должно поставить вас в грубую точку ответа на ваш вопрос, я надеюсь.
источник
re
здесь. Если это отфильтровать ключи с подчеркиванием в них, это не правильный код и не правильное поведение.re.match("_", "reference1_id")
возвратNone
и допустимые столбцы в базе данных могут иметь подчеркивания в своих именах.editable=false
полях. Я просто пытался предоставить что-то, с чем вы могли бы работать, пока не было предоставлено более каноническое решение."_" in string
а неre
в этом случае.in
вместоre
.Здесь много интересных решений. Мое решение состояло в том, чтобы добавить метод as_dict к моей модели с пониманием dict.
В качестве бонуса, это решение в сочетании с пониманием списка по запросу делает хорошее решение, если вы хотите экспортировать свои модели в другую библиотеку. Например, выгрузка ваших моделей в фрейм данных pandas:
источник
(не хотел комментировать)
Хорошо, это на самом деле не зависит от типов. Возможно, я неправильно понял первоначальный вопрос здесь, так что простите, если это так. Если вы создадите serliazers.py, то там вы создадите классы с мета-классами.
Затем, когда вы получите данные в классе представления, вы можете:
Это довольно много, что я имею в разных местах, и он возвращает хороший JSON через JSONRenderer.
Как я уже сказал, это любезно предоставлено DjangoRestFramework, так что стоит посмотреть на это.
источник
Самый простой способ - просто использовать
pprint
, который есть в базовом PythonЭто дает вывод, который выглядит примерно так,
json.dumps(..., indent = 4)
но он правильно обрабатывает странные типы данных, которые могут быть встроены в экземпляр вашей модели, такие какModelState
иUUID
т. Д.Проверено на Python 3.7
источник
Может быть, это поможет вам. Пусть это не скрывает многие отношения, но очень удобно, когда вы хотите отправить свою модель в формате json.
источник
Лучшее решение, которое вы когда-либо видели.
Преобразуйте экземпляр django.db.models.Model и все связанные поля функций ForeignKey, ManyToManyField и @Property в dict.
https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52
источник
Ответ от @zags является исчерпывающим и должен быть достаточным,
но метод # 5 (который является лучшим из IMO) выдает ошибку, поэтому я улучшил вспомогательную функцию.Поскольку OP запрашивал преобразование
many_to_many
полей в список первичных ключей, а не в список объектов, я усовершенствовал функцию, чтобы возвращаемое значение теперь стало сериализуемым в JSON - путем преобразованияdatetime
объектовstr
иmany_to_many
объектов в список идентификаторов.источник
concrete_fields
иm2m_fields
выглядит одинаково, поэтому предполагается, чтоm2m_fields
цикл имеет неправильную реализацию здесь.AttributeError: 'list' object has no attribute 'values_list'
которую я не мог найти причину этого. Я использую Django 2.1.1field.value_from_object
и в результате, изmodel_to_dict
. Я обновил раздел 5 моего ответа, чтобы отразить это.