【问题标题】:Trying to understand JSONField for django postgresql试图了解 django postgresql 的 JSONField
【发布时间】:2017-12-28 12:28:03
【问题描述】:

我正在阅读 JSONField 上的 the docs,这是一种特殊的 postgresql 字段类型。由于我打算创建一个子类JSONField 的自定义字段,并具有能够转换我的Lifts 类的附加功能:

class Lifts(object):
    def __init__(self, series):
        for serie in series:
            if type(serie) != LiftSerie:
                raise TypeError("List passed to constructor should only contain LiftSerie objects")
        self.series = series

class AbstractSerie(object):

    def __init__(self, activity, amount):
        self.activity_name = activity.name
        self.amount = amount

    def pre_json(self):
        """A dict that can easily be turned into json."""
        pre_json = {
            self.activity_name:
                self.amount
        }
        return pre_json

    def __str__(self):
        return str(self.pre_json())

class LiftSerie(AbstractSerie):

    def __init__(self, lift, setlist):
        """ lift should be an instance of LiftActivity.
            setList is a list containing reps for each set
            that has been performed.
        """
        if not (isinstance(setlist, collections.Sequence) and not isinstance(setlist, str)):
            raise TypeError("setlist has to behave as a list and can not be a string.")
        super().__init__(lift, setlist)

我读过hereto_python()from_db_value()Field 类上的两个方法,它们涉及从数据库加载值并反序列化它们。另外,在Field classto_python() 方法的文档字符串中,它说它应该被子类覆盖。所以,我查看了JSONField。你猜怎么着,它不会覆盖它。此外,from_db_value() 甚至没有在Field 上定义(也没有在JOSNField 上定义)。

那么这里发生了什么?这让我们很难理解 JSONField 如何获取值并将它们转换为 json 并将它们存储在数据库中,而当我们查询数据库时则相反。

我的问题总结:

  1. 为什么to_python() 没有在JSONField 中被覆盖?
  2. 为什么from_db_value() 没有在JSONField 中被覆盖?
  3. 为什么from_db_value() 甚至没有在Field 上定义?
  4. JSONField 如何以 python dict 为例,将其转换为 JSON 字符串,并将其存储在数据库中?
  5. 它是如何反其道而行之的?

很抱歉有很多问题,但我真的很想了解这一点,而且文档有点缺乏 IMO。

【问题讨论】:

    标签: python django


    【解决方案1】:

    对于 Django 数据库字段,有相同数据的三种相关状态/表示:表单、python 和数据库。在示例HandField 的情况下,表单/数据库表示是相同的字符串,python 表示是Hand 对象实例。

    JSONField之上的自定义字段的情况下,内部python可能是一个LiftSerie实例,表单表示一个json字符串,发送到数据库的值是一个json字符串,而从数据库接收的值一个由 psycopg2 从 postgres 返回的字符串转换的 json 结构,如果有意义的话。

    就您的问题而言:

    1. 没有自定义python值,所以字段的python数据类型和预期的输入一样。与HandField 示例相比,输入可以是字符串或Hand 实例。在后一种情况下,只返回输入的基本Field.to_python() 实现就足够了。

    2. Psycopg2 已经将数据库值转换为 json,请参见 5。对于其他类型,例如 int/IntegerField,也是如此。

    3. from_db_value 未在基类 Field 中定义,但如果存在,肯定会考虑在内。如果您查看implementation of Field.get_db_converters(),如果Field 具有类似名称的属性,则会将from_db_value 添加到其中。

    4. django.contrib.postgres.JSONField 有一个可选的编码器参数。默认情况下,它使用json.dumps without an encoder 将json结构转换为JSON字符串。

    5. psycopg2 自动从数据库类型转换为 python 类型。它被称为adaptationDocumentation for JSON adaptation 解释了它是如何工作的并且可以自定义。

    请注意,在实现自定义字段时,我建议在开发过程中为其编写测试,尤其是在机制尚未完全理解的情况下。您可以在例如django-localflavor 中获得此类测试的灵感。

    【讨论】:

    • 非常感谢您花时间回答我的问题。 on 1:那么,由于to_python()clean() 期间运行表单,这是否意味着JSONField 期望从表单收集的值是正确的json 字符串?
    • django.contrib.postgres.forms.JSONField implements 从字符串到 JSON 结构的对话。
    • 自定义如下:从您扩展的字段更改功能。
    • Psycopg2 从 db 字符串转换为 python 结构,forms.JSONFields 从表单字符串转换为 python 结构。基本上相同的转换,但在不同的地方。
    【解决方案2】:

    简短的回答是,to_python 和 from_db_value 都返回应该序列化为 JSON 且没有编码错误的 Python 字符串,所有条件都相同。

    如果您对字符串没问题,那很好,但我通常会覆盖 Django 的 JSONFields 的 from_db_value 方法以返回字典或列表,而不是在我的代码中使用的字符串。我为此创建了一个自定义字段。

    对我来说,Json 字段的全部意义在于能够以字典或列表的形式与其值进行交互。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-16
      • 2018-05-15
      • 1970-01-01
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      相关资源
      最近更新 更多