64

我需要在 Django 模型中存储一些数据。这些数据并不等于模型的所有实例。

起初我考虑对模型进行子类化,但我试图保持应用程序的灵活性。如果我使用子类,每次我需要一种新的对象时,我都需要创建一个完整的类,这不好。我也会得到很多子类,只是为了存储一对额外的字段。

我真的觉得字典是最好的方法,但是 Django 文档中没有关于在 Django 模型中存储字典的内容(或者我找不到它)。

有什么线索吗?

4

14 回答 14

44

如果它真的像您要查找的任意数据那样是字典,您可能可以使用两级设置,其中一个模型是容器,另一个模型是键值对。您将创建容器的一个实例,创建每个键值实例,并将键值实例集与容器实例相关联。就像是:

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 解决方案则不会。

于 2008-12-31T08:19:28.807 回答
18

如果您不需要通过任何这些额外数据进行查询,则可以将其存储为序列化字典。用于repr将字典转为字符串,并将eval字符串转回字典。注意 eval 字典中没有用户数据,或者使用safe_eval实现。

例如,在您的createupdate方法中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])
于 2008-12-31T03:39:18.747 回答
16

可以在这里找到另一个干净快速的解决方案:https ://github.com/bradjasper/django-jsonfield

为方便起见,我复制了简单的说明。

安装

pip install jsonfield

用法

from django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
    json = JSONField()
于 2013-07-31T12:50:28.747 回答
14

我通过 google 的第 4 个结果来到这篇文章“django store object”

有点晚了,但django-picklefield对我来说是个不错的解决方案。

来自文档的示例:

要使用,只需在模型中定义一个字段:

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

并将您喜欢的任何内容(只要它是可腌制的)分配给该字段:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
于 2011-09-19T10:10:04.323 回答
8

正如 Ned 回答的那样,如果您使用字典方法,您将无法查询“某些数据”。

如果您仍然需要存储字典,那么到目前为止,最好的方法是 Marty Alchin 的新书Pro Django中记录的 PickleField 类。此方法仅在需要时使用 Python 类属性来腌制/取消腌制存储在模型字段中的 Python 对象。

这种方法的基础是使用 django 的contibute_to_class方法动态地向模型添加一个新字段,并使用 getattr/setattr 进行按需序列化。

我能找到的为数不多的在线示例之一是JSONField的定义。

于 2008-12-31T07:44:46.600 回答
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的建议通过序列化将值转换为单个列;但是,如果您必须使用 RDBMS,Django 模型继承可能是要走的路。值得注意的是,它将为每个派生级别创建一对一的外键关系。

于 2008-12-31T07:09:29.697 回答
6

这个问题很老,但我遇到了同样的问题,到此结束,选择的答案无法再解决我的问题。

如果您想在 Django 或 REST Api 中存储字典,或者用作前端的对象,或者因为您的数据不一定具有相同的结构,我使用的解决方案可以帮助您。

在您的 API 中保存数据时,使用json.dump()方法能够以正确的 json 格式存储它,如本问题所述。

如果您使用此结构,您的数据将已经采用适当的 json 格式,以便在您的 ajax(或其他)调用中使用JSON.parse()在前端调用。

于 2018-08-02T08:56:20.180 回答
5

我使用文本字段和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)

于 2019-05-05T04:55:55.337 回答
3

“不等于模型的所有实例”对我来说听起来很适合“无模式数据库”。CouchDB是这种方法的典型代表,您可能会考虑这一点。

在一个项目中,我将几个在 Django ORM 上表现不佳的表移到了 CouchDB,我对此感到非常满意。我使用couchdb-python没有任何 Django 特定的 CouchDB 模块。可以在此处找到数据模型的描述。从 Django 中的 5 个“模型”到 Django 中的 3 个“模型”和一个 CouchDB“数据库”实际上稍微减少了我的应用程序中的总代码行数。

于 2009-01-04T12:28:20.570 回答
3

Django-Geo 包含一个“DictionaryField”,您可能会觉得有帮助:

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

通常,如果您不需要跨数据查询,请使用非规范化方法来避免额外查询。用户设置就是一个很好的例子!

于 2009-05-13T16:50:37.157 回答
3

我同意您需要避免将其他结构化数据填充到单个列中。但是如果你必须这样做,Django 有一个内置的XMLField

Django 片段中还有JSONField

于 2009-05-13T18:05:44.727 回答
2

仔细想想,找出每个数据集的共同点……然后定义你的模型。它可能需要或不需要使用子类。不应该避免表示共性的外键,而是在有意义时鼓励它们。

将随机数据填充到 SQL 表中并不聪明,除非它是真正的非关系数据。如果是这种情况,请定义您的问题,我们或许可以提供帮助。

于 2008-12-31T05:54:12.143 回答
1

如果您使用 Postgres,则可以使用 hstore 字段:https ://docs.djangoproject.com/en/1.10/ref/contrib/postgres/fields/#hstorefield 。

于 2016-08-30T19:36:59.490 回答
0

我知道这是一个老问题,但今天(2021 年)最干净的选择是使用原生 JSONfield(自 django 3.1 起)

文档:https ://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.JSONField

您只需在类模型中创建一个名为 jsonfield 的模型字段,然后瞧

于 2021-12-08T19:59:42.310 回答