如何在 Django 数据库模型的字段中存储字典

Posted

技术标签:

【中文标题】如何在 Django 数据库模型的字段中存储字典【英文标题】:How to store a dictionary in a Django database model's field 【发布时间】:2012-03-29 23:51:34 【问题描述】:

我需要在模型字段中保存字典。我该怎么做?

例如我有这个代码:

def create_random_bill(self):
    name_chars = re.compile("[a-zA-Z0-9 -_]")
    bill_name = "".join(random.choice(name_chars for x in range(10)))
    rand_products = random.randint(1,100)
    for x in rand_products:
        bill_products = 
    new_bill = Bill.new(name=bill_name, date=datetime.date, products=bill_products)
    new_bill.save()

我为“bill_products=”写什么,这样它可以保存一些随机产品,从我的产品模型到这个账单?

这是账单的型号说明:

class Bill(models.Model):
    name = models.CharField(max_length=255)
    date = models.DateTimeField(auto_now_add=True)
    products = models.ManyToManyField(Product, related_name="bills")

还有产品型号说明:

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.IntegerField()

如果还有什么我应该添加的,请发表评论。谢谢!

【问题讨论】:

什么是“python 数据库模型”?您是否使用特定的 ORM 或框架?这看起来有点“django-ish” 是的,它是 Django。我刚刚开始使用它,所以我可能会将“Python”与“Django”混为一谈。我改一下标题。 【参考方案1】:

我刚刚发现了django-jsonfield 包,

是一个可重用的 Django 字段,允许您在模型中存储经过验证的 JSON。

看起来是实现您想要的可行选择。

【讨论】:

感谢您的更新。很高兴知道,即使这个问题很久以前就已经解决了。 自 2017 年以来未维护此 repo。github.com/adamchainz/django-jsonfield 是第二个解决方案的一个分支。此外,PostGres 原生支持 JSON 字段:docs.djangoproject.com/en/dev/ref/contrib/postgres/fields/…【参考方案2】:

在模型中存储 JSON 表示的一种便捷方法是使用自定义字段类型:

class JSONField(models.TextField):
    """
    JSONField is a generic textfield that neatly serializes/unserializes
    JSON objects seamlessly.
    Django snippet #1478

    example:
        class Page(models.Model):
            data = JSONField(blank=True, null=True)


        page = Page.objects.get(pk=5)
        page.data = 'title': 'test', 'type': 3
        page.save()
    """

    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        if value == "":
            return None

        try:
            if isinstance(value, basestring):
                return json.loads(value)
        except ValueError:
            pass
        return value

    def get_db_prep_save(self, value, *args, **kwargs):
        if value == "":
            return None
        if isinstance(value, dict):
            value = json.dumps(value, cls=DjangoJSONEncoder)
        return super(JSONField, self).get_db_prep_save(value, *args, **kwargs)

我保存了这个 utils/fields.py 和我的模型 from utils.fields import JSONField。 django-annoying 应用程序中还有更多好东西,这就是这个 sn-p 的来源。

【讨论】:

【参考方案3】:

使用自定义字段类型是我的首选解决方案 - 我宁愿拥有几行自定义代码,也不愿为单个字段类型支持整个 3rd 方库。 Tony Abou-Assaleh 有一个很好的解决方案,但不适用于较新版本的 Django。

已验证可与 Django 1.10.4 一起使用

import json

from django.db import models
from django.core.serializers.json import DjangoJSONEncoder


class JSONField(models.TextField):
    """
    JSONField is a generic textfield that neatly serializes/unserializes
    JSON objects seamlessly.
    Django snippet #1478

    example:
        class Page(models.Model):
            data = JSONField(blank=True, null=True)


        page = Page.objects.get(pk=5)
        page.data = 'title': 'test', 'type': 3
        page.save()
    """

    def to_python(self, value):
        if value == "":
            return None

        try:
            if isinstance(value, str):
                return json.loads(value)
        except ValueError:
            pass
        return value

    def from_db_value(self, value, *args):
        return self.to_python(value)

    def get_db_prep_save(self, value, *args, **kwargs):
        if value == "":
            return None
        if isinstance(value, dict):
            value = json.dumps(value, cls=DjangoJSONEncoder)
        return value

【讨论】:

这不处理序列化 (manage.py dumpdata),不处理 db 中的查找,不处理 Django adming 中的编辑(因为显示的表示是序列化 dict 的表示)等等。也许最后使用第 3 方库可以避免您遇到错误。【参考方案4】:

可能最干净的做法是创建另一个“产品”表并建立多对多关系。 (见这里:https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships。在文档中,他们使用了一个披萨有很多配料的例子。)

另一种选择是序列化您的 bill_products。在这种情况下,您会执行以下操作:

bill_products = json.dumps([rand_products])

这将在 for 循环之外(尽管在您上面的示例中,rand_products 只是一个值,因此您需要修复它)。

【讨论】:

如果你能提供一个例子,那就太好了。恐怕我不明白如何准确地将多对多关系转换为我的代码。在该字段中保存带有产品名称的数组,我是否走在正确的思路上?或者我可以用更简单的方法来做吗? @reos 你走在正确的轨道上。这是一个完整的例子:djangoproject.com/documentation/0_91/models/many_to_many【参考方案5】:

如果 postgres 是您的后端,请考虑使用 django 原生支持的 hstore 字段

【讨论】:

感谢您的回答,不过这个问题早就得到解答和解决了。后端是 SQLLite【参考方案6】:

你可以使用pickle模块的序列化/反序列化:

http://docs.python.org/library/pickle.html

【讨论】:

【参考方案7】:

我认为我会将字段创建为 models.CharField() 然后将字典编码为 JSON 字符串并将该字符串保存到数据库中。然后,您可以在读出时将 JSON 字符串解码回字典。

【讨论】:

我添加了比尔的型号说明。【参考方案8】:

如果使用 PostGres,您可以将其存储在原生支持的 JSON 字段中: https://docs.djangoproject.com/en/dev/ref/contrib/postgres/fields/#jsonfield

否则我会推荐 @ramiro 使用 3rd 方库 https://***.com/a/16437627/803174回答

【讨论】:

【参考方案9】:

根据 Django doc 你可以使用:

from django.contrib.postgres.fields import JSONField
from django.db import models

class Dog(models.Model):
    name = models.CharField(max_length=200)
    data = JSONField()

    def __str__(self):
        return self.name

并用这个创建:

Dog.objects.create(name='Rufus', data=
     'breed': 'labrador',
     'owner': 
         'name': 'Bob',
         'other_pets': [
             'name': 'Fishy',
         ],
     ,
)

希望对你有帮助。

【讨论】:

以上是关于如何在 Django 数据库模型的字段中存储字典的主要内容,如果未能解决你的问题,请参考以下文章

django模型,如何动态设置查询的字段?

django 有没有内置用字典更新模型的方法

如何在 Django 模型中存储任意名称/值键对?

在 Django 模型中保存时区

Django - 日期和时间字段说明

如何限制 Django 模型中数值字段的最大值?