Подтвердить что ты не робот

Как хранить словарь на модели Django?

Мне нужно сохранить некоторые данные в модели Django. Эти данные не равны всем экземплярам модели.

Сначала я подумал о подклассификации модели, но Im пытался сохранить приложение гибким. Если я использую подклассы, мне нужно создавать целый класс каждый раз, когда мне нужен новый вид объекта, и это нехорошо. Ill также в конечном итоге с большим количеством подклассов только для хранения пары дополнительных полей.

Я действительно чувствую, что словарь будет лучшим подходом, но ничего не стоит в документации Django о хранении словаря в модели Django (или я не могу найти его).

Любые подсказки?

4b9b3361

Ответ 1

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

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)

Это не очень, но это позволит вам получить доступ к внутренним словам словаря, используя DB, тогда как решение pickle/serialize не будет.

Ответ 2

Если вам не нужно запрашивать какие-либо из этих дополнительных данных, то вы можете сохранить их как сериализованный словарь. Используйте 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])

Ответ 3

Я пришел к этому сообщению с помощью google 4-го результата для "объекта хранения django"

Немного поздно, но django-picklefield выглядит как хорошее решение для меня.

Пример из документа doc:

Чтобы использовать, просто определите поле в своей модели:

>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>>     args = PickledObjectField()

и назначьте все, что вам нравится (до тех пор, пока оно подбирается) в поле:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()

Ответ 4

Другое чистое и быстрое решение можно найти здесь: https://github.com/bradjasper/django-jsonfield

Для удобства я скопировал простые инструкции.

Установить

pip install jsonfield

Использование

from django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
    json = JSONField()

Ответ 5

Как сказал Нед, вы не сможете запросить "некоторые данные", если используете словарь.

Если вам по-прежнему нужно хранить словари, то лучшим подходом, безусловно, является класс PickleField, задокументированный в новой книге Marty Alchin Pro Django. Этот метод использует свойства класса Python для разметки/распаковки объекта python только по запросу, который хранится в поле модели.

Основой этого подхода является использование метода django contibute_to_class для динамического добавления нового поля в вашу модель и использования getattr/setattr для выполняйте сериализацию по требованию.

Один из немногих онлайн-примеров, которые я смог найти, похож на это определение JSONField.

Ответ 6

Я не уверен точно в характере проблемы, которую вы пытаетесь решить, но это звучит любопытно похоже на Google App Engine BigTable Expando.

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. Может быть стоит посмотреть, если это лучший способ выразить свои модели.

Традиционные модели реляционных баз данных не обладают такой гибкостью для добавления столбцов. Если ваши типы данных достаточно просты, вы можете отказаться от традиционной философии RDBMS и взломать значения в один столбец посредством сериализации, поскольку @Ned Batchelder предлагает; однако, если вам нужно использовать РСУБД, наследование модели Django, вероятно, является способом выхода. Примечательно, что он создаст отношение "один к одному" внешнего ключа для каждого уровня вывода.

Ответ 7

Быть "не равным всем экземплярам модели" звучит для меня как хорошее совпадение для "базы данных без схем". CouchDB является дочерним плакатом для этого подхода, и вы можете подумать об этом.

В проекте я переместил несколько таблиц, которые никогда не играли очень хорошо с Django ORM до CouchDB, и я вполне доволен этим. Я использую couchdb-python без каких-либо Django-специфичных модулей CouchDB. Описание модели данных можно найти здесь. Движение из пяти "моделей" в Django до 3 "моделей" в Django и одной базе данных CouchDB фактически немного уменьшило общие строки кода в моем приложении.

Ответ 8

Я согласен, что вам нужно воздержаться от наложения других структурированных данных в один столбец. Но если вы должны это сделать, Django имеет XMLField.

Там также JSONField в Djipo snipplets.

Ответ 9

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

Если вы хотите хранить словари в Django или REST Api, которые будут использоваться как объекты в вашем интерфейсе, или потому что ваши данные не обязательно будут иметь одинаковую структуру, то решение, которое я использовал, может вам помочь.

При сохранении данных в вашем API используйте метод json.dump(), чтобы иметь возможность сохранить их в правильном формате json, как описано в этом вопросе.

Если вы используете эту структуру, ваши данные уже будут в соответствующем формате json, который будет вызываться во внешнем интерфейсе с помощью JSON.parse() в вашем вызове ajax (или как угодно).

Ответ 10

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

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

Ответ 11

Django-Geo включает в себя "DictionaryField", который может вам пригодиться:

http://code.google.com/p/django-geo/source/browse/trunk/fields.py?r=13#49

В общем случае, если вам не нужно запрашивать данные, используйте денормализованный подход, чтобы избежать дополнительных запросов. Пользовательские настройки - довольно хороший пример!

Ответ 13

Я использую текстовое поле и 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)