Мне нужно сохранить некоторые данные в модели Django. Эти данные не совпадают для всех экземпляров модели.
Сначала я думал о создании подкласса модели, но стараюсь сохранить гибкость приложения. Если я использую подклассы, мне нужно будет создавать целый класс каждый раз, когда мне понадобится новый тип объекта, а это бесполезно. Я также получу много подклассов только для хранения пары дополнительных полей.
Я действительно считаю, что словарь был бы лучшим подходом, но в документации Django нет ничего о хранении словаря в модели Django (или я не могу его найти).
Какие-нибудь подсказки?






Если вам не нужно запрашивать какие-либо из этих дополнительных данных, вы можете сохранить их как сериализованный словарь. Используйте repr, чтобы превратить словарь в строку, и eval, чтобы превратить строку обратно в словарь. Позаботьтесь о eval, чтобы в словаре не было пользовательских данных, или используйте реализацию safe_eval.
Например, в методах create и update вашего views вы можете добавить:
if isinstance(request.data, dict) == False:
req_data = request.data.dict().copy()
else:
req_data = request.data.copy()
dict_key = 'request_parameter_that_has_a_dict_inside'
if dict_key in req_data.keys() and isinstance(req_data[dict_key], dict):
req_data[dict_key] = repr(req_data[dict_key])
Подумайте и найдите общие черты каждого набора данных ... затем определите свою модель. Это может потребовать использования подклассов или нет. Не следует избегать внешних ключей, представляющих общие черты, но поощрять их, когда они имеют смысл.
Вставлять случайные данные в таблицу SQL неразумно, если только это действительно нереляционные данные. В таком случае определите свою проблему, и мы сможем помочь.
+1: не просто помещайте объекты Python в таблицу наугад.
Я не совсем уверен в природе проблемы, которую вы пытаетесь решить, но это странно похоже на BigTable Expando от Google App Engine.
Expandos позволяет указывать и сохранять дополнительные поля в экземпляре объекта, поддерживаемом базой данных, во время выполнения. Цитата из документов:
import datetime
from google.appengine.ext import db
class Song(db.Expando):
title = db.StringProperty()
crazy = Song(title='Crazy like a diamond',
author='Lucy Sky',
publish_date='yesterday',
rating=5.0)
crazy.last_minute_note=db.Text('Get a train to the station.')
Google App Engine в настоящее время поддерживает как Python, так и платформу Django. Возможно, стоит посмотреть, если это лучший способ выразить ваши модели.
Традиционные модели реляционных баз данных не обладают такой гибкостью добавления столбцов. Если ваши типы данных достаточно просты, вы можете отказаться от традиционной философии РСУБД и поместить значения в один столбец с помощью сериализации, как предлагает @Ned Batchelder; однако, если вы используете имеют для использования СУБД, наследование модели Django, вероятно, будет правильным решением. В частности, он создаст отношение взаимно однозначный внешний ключ для каждого уровня деривации.
Как ответил Нед, вы не сможете запросить «некоторые данные», если будете использовать словарный подход.
Если вам все еще нужно хранить словари, то лучшим подходом, безусловно, является класс PickleField, описанный в новой книге Марти Алчина Pro Django. Этот метод использует свойства класса Python для выделения / извлечения объекта Python только по запросу, который хранится в поле модели.
Основы этого подхода - использовать метод django contibute_to_class для динамического добавления нового поля в вашу модель и использовать getattr / setattr для сериализации по запросу.
Один из немногих похожих онлайн-примеров, которые я смог найти, - это определение JSONField.
Если это действительно словарь, как произвольные данные, которые вы ищете, вы, вероятно, можете использовать двухуровневую настройку с одной моделью, которая является контейнером, и другой моделью, которая представляет собой пары ключ-значение. Вы должны создать экземпляр контейнера, создать каждый из экземпляров "ключ-значение" и связать набор экземпляров "ключ-значение" с экземпляром контейнера. Что-то вроде:
class Dicty(models.Model):
name = models.CharField(max_length=50)
class KeyVal(models.Model):
container = models.ForeignKey(Dicty, db_index=True)
key = models.CharField(max_length=240, db_index=True)
value = models.CharField(max_length=240, db_index=True)
Это некрасиво, но это позволит вам получить доступ / искать внутренности словаря с помощью БД, тогда как решение pickle / serialize не будет.
Единственным недостатком является то, что последует дополнительный запрос к БД.
Еще одним недостатком является то, что у вас есть ровно один «уровень» данных, вы не можете создавать многоуровневые сложные данные в стиле JSON. (но тем не менее хорошая идея)
Нашел хорошее расширение этого решения: djangosnippets.org/snippets/2451 этот парень расширил словарь на все функции словаря Python
Так как это называется?
@NickPerkins Вы можете сделать это рекурсивным, если Dicty содержит поле parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True). Любой dict без родителя - это объект верхнего уровня. Тадааа! Да, было бы неплохо, если бы value указывал на другой словарь вместо использования специального поля, но ¯_ (ツ) _ / ¯ ... В качестве альтернативы на KeyVal добавьте child = models.ForeignKey('Dicty', models.CASCADE, null=True, blank=True)
То, что «не равно всем экземплярам модели», звучит для меня как хорошее совпадение с «базой данных без схемы». CouchDB является образцом этого подхода, и вы можете это рассмотреть.
В одном проекте я переместил несколько столов, которые никогда не играли очень хорошо с Django ORM, на CouchDB, и я вполне доволен этим. Я использую couchdb-python без каких-либо модулей CouchDB, специфичных для Django. Описание модели данных можно найти в здесь. Переход от пяти «моделей» в Django к 3 «моделям» в Django и одной «базе данных» CouchDB фактически немного сократил общее количество строк кода в моем приложении.
Django-Geo включает поле DictionaryField, которое может оказаться полезным:
http://code.google.com/p/django-geo/source/browse/trunk/fields.py?r=13#49.
В общем, если вам не нужно запрашивать данные, используйте денормализованный подход, чтобы избежать дополнительных запросов. Пользовательские настройки - хороший тому пример!
Я пришел к этому сообщению по четвертому результату Google для "объекта хранилища django"
Немного поздно, но джанго-рассол мне кажется хорошим решением.
Пример из документа:
Чтобы использовать, просто определите поле в своей модели:
>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>> args = PickledObjectField()
и назначьте в поле все, что вам нравится (при условии, что это можно выбрать):
>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
Еще одно чистое и быстрое решение можно найти здесь: https://github.com/bradjasper/django-jsonfield
Для удобства скопировал простые инструкции.
Установить
pip install jsonfield
Применение
from django.db import models
from jsonfield import JSONField
class MyModel(models.Model):
json = JSONField()
Это удобный способ использования, но по умолчанию он не поддерживает проверку словаря. Поэтому, если я отправляю int или строку, они напрямую сохраняют эти данные.
from django.contrib.postgres import fields для PostgreSQL
Если вы используете Postgres, вы можете использовать поле hstore: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield.
Это старый вопрос, но у меня была та же проблема, которая закончилась здесь, и выбранный ответ больше не мог решить мою проблему.
Если вы хотите хранить словари в Django или REST Api, либо для использования в качестве объектов в вашем интерфейсе, либо потому, что ваши данные не обязательно будут иметь одинаковую структуру, решение, которое я использовал, может вам помочь.
При сохранении данных в вашем API используйте метод json.dump (), чтобы иметь возможность хранить их в надлежащем формате json, как описано в этом вопрос.
Если вы используете эту структуру, ваши данные уже будут в соответствующем формате json, которые будут вызываться во внешнем интерфейсе с помощью JSON.parse () в вашем вызове ajax (или другом).
Я использую текстовое поле и json.loads() / json.dumps()
models.py
import json
from django.db import models
class Item(models.Model):
data = models.TextField(blank=True, null=True, default='{}')
def save(self, *args, **kwargs):
## load the current string and
## convert string to python dictionary
data_dict = json.loads(self.data)
## do something with the dictionary
for something in somethings:
data_dict[something] = some_function(something)
## if it is empty, save it back to a '{}' string,
## if it is not empty, convert the dictionary back to a json string
if not data_dict:
self.data = '{}'
else:
self.data = json.dumps(data_dict)
super(Item, self).save(*args, **kwargs)
"некоторые данные" - плохо определены. Без какой-либо модели данных или других подсказок нет ответа.