Преобразовать объект модели Django в dict, чтобы все поля были неповрежденными

Как преобразовать объект модели django в dict со всеми его полями? Все в идеале включают внешние ключи и поля с возможностью редактирования = False.

Позвольте мне уточнить. Предположим, у меня есть модель django, например:

from django.db import models class OtherModel(models.Model): pass class SomeModel(models.Model): 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") 

В терминале я сделал следующее:

 other_model = OtherModel() other_model.save() instance = SomeModel() instance.value = 1 instance.value2 = 2 instance.reference1 = other_model instance.save() instance.reference2.add(other_model) instance.save() 

Я хочу преобразовать это в следующий словарь:

 {'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1, 'value2': 2} 

Вопросы с неудовлетворительными ответами:

Django: преобразование всего набора объектов модели в один словарь

Как я могу превратить объекты Django Model в словарь и все еще иметь свои внешние ключи?

6 Solutions collect form web for “Преобразовать объект модели Django в dict, чтобы все поля были неповрежденными”

Существует множество способов конвертировать экземпляр в словарь, с разной степенью обработки угловых дел и близостью к желаемому результату.


1. instance.__dict__

 instance.__dict__ 

который возвращается

 {'_reference1_cache': <OtherModel: OtherModel object>, '_state': <django.db.models.base.ModelState at 0x1f63310>, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51, 844795, tzinfo=<UTC>), 'id': 1L, 'reference1_id': 1L, 'value': 1, 'value2': 2} 

Это, безусловно, самое простое, но отсутствует reference2, reference1 имеет неправильное название, и в нем есть две дополнительные вещи.


2. model_to_dict

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

который возвращается

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

Это единственная ссылка со ссылкой2, но отсутствует неотредактируемые поля.


3. model_to_dict с полями

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

который возвращается

 {u'id': 1L, 'reference1': 1L, 'value': 1} 

Это строго хуже, чем стандартный вызов model_to_dict.


4. query_set.values ​​()

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

который возвращается

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

Это тот же результат, что и instance.__dict__ но без дополнительных полей.


5. Пользовательская функция

Большинство ответов отвечало на код модели django model_to_dict. Он явно удаляет не редактируемые поля, поэтому удаление этой проверки приводит к следующему коду, который ведет себя по желанию:

 from django.db.models.fields.related import ManyToManyField def to_dict(instance): opts = instance._meta data = {} for f in opts.concrete_fields + opts.many_to_many: if isinstance(f, ManyToManyField): if instance.pk is None: data[f.name] = [] else: data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True)) else: data[f.name] = f.value_from_object(instance) return data 

Хотя это самый сложный вариант, вызов to_dict(instance) дает нам точно желаемый результат:

 {'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1, 'value2': 2} 

Бонусный раунд

Если вы хотите, чтобы модель django имела лучший интерфейс командной строки на python, у вас есть дочерние классы ваших моделей:

 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)) else: data[f.name] = f.value_from_object(self) return data class Meta: abstract = True 

Так, например, если мы определим наши модели как таковые:

 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") 

Вызов SomeModel.objects.first() теперь дает результат следующим образом:

 {'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), 'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]} 

Если вы хотите определить свой собственный метод to_dict, например, предложенный @karthiker, то это просто переваривает эту проблему до проблемы с наборами.

 >>># 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} 

Нам нужно удалить неверно маркированные внешние ключи от otherDict .

Для этого мы можем использовать цикл, который создает новый словарь, в котором есть каждый элемент, кроме тех, у которых есть символы подчеркивания. Или, чтобы сэкономить время, мы можем просто добавить их к оригинальному dict, поскольку словари просто устанавливаются под капотом.

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

Таким образом, мы остаемся со следующим dict :

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

И ты просто возвращаешь это.

С другой стороны, вы не можете использовать символы подчеркивания в именах editable = false. С другой стороны, это будет работать для любого набора полей, в которых пользовательские поля не содержат символов подчеркивания.

–РЕДАКТИРОВАТЬ–

Это не лучший способ сделать это, но он может работать как временное решение, пока не будет найден более прямой метод.

В приведенном ниже примере dict будет сформирован на основе model_to_dict, а otherDict будет сформирован по методу значений фильтра. Я бы сделал это с самими моделями, но я не могу заставить мою машину принимать otherModel.

 >>> 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]} >>> 

Надеюсь, это поставит вас в приблизительный приблизительный ответ на ваш вопрос.

Я нашел аккуратное решение, чтобы получить результат:

Предположим, у вас есть объект модели o :

Просто позвони:

 type(o).objects.filter(pk=o.pk).values().first() 

Может быть, это поможет вам. Пусть это не скрывает многих во многих отношениях, но очень удобно, когда вы хотите отправить свою модель в формате 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 

(не хотел комментировать)

Хорошо, на самом деле это не зависит от типов. Возможно, я неправильно понял первоначальный вопрос, поэтому простите меня, если это так. Если вы создадите serliazers.py, тогда там вы создадите классы с метаклассами.

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

Затем, когда вы получаете данные в классе вида, вы можете:

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

Это в значительной степени то, что у меня есть в гадости мест, и он возвращает хороший JSON через JSONRenderer.

Как я уже сказал, это любезно предоставлено DjangoRestFramework, поэтому стоит посмотреть на это.

Здесь много интересных решений. Моим решением было добавить метод as_dict для моей модели с пониманием dict.

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

В качестве бонуса это решение в сочетании с пониманием списка по запросу делает хорошее решение, если вы хотите экспортировать свои модели в другую библиотеку. Например, сброс ваших моделей в кадр данных pandas:

 pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()]) 
  • Вывести дочерний тип с Django MTI или указать тип как поле?
  • Наследие Django admin Наследование возможно?
  • Добавление внешнего ключа в модель Django
  • Как кэшировать разбитый на страницы запрос Django
  • Запретить удаление в модели Django
  • Как установить другой заголовок Inline в Django Admin?
  • Django Left Outer Join
  • Пользовательский заказ в Django
  •  
    Interesting Posts for Van-Lav

    Построение векторных полей двумя разными способами (колчан / поток), в результате чего не совпадают графики – Matplotlib

    Прогнозирование ARMA вне выборки с помощью statsmodels

    Python – округляется до ближайших десяти

    как читать объект JSON с помощью ajax из приложения python wsgi

    Установите Colorbar Range в matplotlib

    Как запустить сервер ipython для ноутбука при загрузке в качестве демона

    Прерывистая ошибка потока Python, «основной поток не находится в основном цикле»

    Если x является значением в этом dict … Python

    записывать строку в файл по новой строке каждый раз?

    Установка расширения hstore в тестах django носа

    Обработка очень большого набора данных в python – ошибка памяти

    преобразовать строку json в объект python

    Использование WordNet для определения семантического сходства между двумя текстами?

    Можно ли использовать «exe installers» с pip?

    Python Tkinter after () Выполняется только один раз

    Python - лучший язык программирования в мире.