如何在Django模型上存储字典?

Ati*_*nch 50 python django orm persistence django-models

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

起初我考虑过继承模型,但我试图保持应用程序的灵活性.如果我使用子类,每次需要一种新的对象时我都需要创建一个完整的类,这并不好.我最终会得到很多子类来存储一对额外的字段.

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

有线索吗?

Par*_*and 38

如果它真的像你正在寻找的任意数据字典,你可以使用一个两级设置,一个模型是一个容器,另一个模型是键值对.您将创建容器的实例,创建每个键值实例,并将键值实例集与容器实例相关联.就像是:

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)
Run Code Online (Sandbox Code Playgroud)

它不漂亮,但它会让你使用数据库访问/搜索字典的内部,而pickle/serialize解决方案则不会.

  • 找到了这个解决方案的一个很好的扩展:https://djangosnippets.org/snippets/2451/这个家伙将字典扩展到所有pythonic字典函数 (8认同)
  • 唯一的缺点是随之而来的是额外的数据库查询 (4认同)
  • 另一个缺点是您只有一个"级别"的数据,您无法创建多级复杂的JSON样式数据.(但好主意) (2认同)
  • @NickPerkins您可以通过让“Dicty”包含字段“parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, Blank=True)”来使其递归。任何没有父对象的字典都是顶级对象。哒哒哒!是的,如果 `value` 指向另一个字典而不是使用特殊字段,那就太好了,但是 ¯\_(ツ)_/¯... 或者在 `KeyVal` 上添加 `child = models.ForeignKey('Dicty', models) .CASCADE,null=True,空白=True)` (2认同)

Ned*_*der 15

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


Sté*_*ane 11

我通过google的4rth结果来到这个帖子"django store object"

有点晚了,但是django-picklefield对我来说看起来很好.

来自doc的示例:

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

>>> from picklefield.fields import PickledObjectField
>>> class SomeObject(models.Model):
>>>     args = PickledObjectField()
Run Code Online (Sandbox Code Playgroud)

并将任何你喜欢的东西(只要它可以选择)分配到该字段:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()
Run Code Online (Sandbox Code Playgroud)


ode*_*fos 11

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

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

安装

pip install jsonfield
Run Code Online (Sandbox Code Playgroud)

用法

from django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
    json = JSONField()
Run Code Online (Sandbox Code Playgroud)

  • `JSONField` 可直接从 `django.db.models` 获取: `from django.db.models import JSONField` 文档中的使用详细信息:https://docs.djangoproject.com/en/4.0/ref/models/fields/ #django.db.models.JSONField (4认同)

Van*_*ale 7

正如Ned所说,如果你使用字典方法,你将无法查询"某些数据".

如果你仍然需要存储词典,那么到目前为止,最好的方法是在Marty Alchin的新书Pro Django中记录的PickleField类.此方法使用Python类属性仅在需要时对存储在模型字段中的python对象进行pickle/unpickle.

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

我能找到的为数不多的在线示例之一就是JSONField的这个定义.


Luc*_*ani 6

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

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

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

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


cdl*_*ary 5

我不确定你要解决的问题的性质,但它听起来与谷歌应用引擎的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.')
Run Code Online (Sandbox Code Playgroud)

Google App Engine目前支持Python和Django框架.如果这是表达模型的最佳方式,可能值得研究.

传统的关系数据库模型没有这种列添加灵活性.如果您的数据类型足够简单,您可以打破传统的RDBMS原则,并通过序列化将值破解为单个列,如@Ned Batchelder所建议的那样; 但是,如果你必须使用RDBMS,那么Django模型继承可能就是这样.值得注意的是,它将为每个派生级别创建一对一的外键关系.


Gra*_*uff 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)

Run Code Online (Sandbox Code Playgroud)


Jos*_*osé 5

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

\n

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

\n

您只需在类模型内的模型中创建一个名为 jsonfield 的字段,然后 voil\xc3\xa1

\n