试图了解django postgresql的JSONField

时间:2017-12-28 12:28:03

标签: python django

我在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)

我已阅读here to_python()from_db_value()Field类中的两个方法,这些方法涉及从数据库加载值并对其进行反序列化。此外,在Field class上的to_python()方法的docstring中,它表示它应该被子类覆盖。所以,我查看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. 它是如何反过来的?
  6. 很抱歉很多问题,但我真的很想理解这一点,而且文档有点缺乏IMO。

2 个答案:

答案 0 :(得分:2)

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

如果自定义字段位于JSONField之上,则内部python可能是LiftSerie实例,表单表示为json字符串,值为json字符串发送给数据库的值和值从数据库中收到一个由psycopg2转换的json结构,如果有意义的话,将从postgres返回的字符串中获取。

就你的问题而言:

  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(),如果from_db_value具有名称相同的属性,则会Field添加django.contrib.postgres.JSONField

  4. <script src="assets/extraQU/extraQU.js"></script> 有一个可选的编码器参数。默认情况下,它使用json.dumps without an encoder将json结构转换为JSON字符串。

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

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

答案 1 :(得分:0)

简单的答案是,to_python和from_db_value都返回python字符串,这些字符串应序列化为JSON,且所有条件均相同。

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

对我来说,Json字段的全部要点是能够与其作为字典或列表的值进行交互。