Django" deconstruct"的目的是什么?模型场函数?

时间:2016-01-01 17:36:25

标签: python django

为了开发自定义Django模型字段,我正在阅读文档。

我已经开发了我的自定义字段(几乎与示例HandField相同:一个映射在Python类上的字段...唯一的区别是我从models.CharField继承而不是models.Field)。

from external_library import ExternalClass

class ExternalClassField(models.CharField):
    description = "An ExternalClass field"

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 14
        super(ExternalClassField, self).__init__(*args, **kwargs)

    def from_db_value(self, value, expression, connection, context):
        if value is None:
            return value
        return ExternalClass(value)

    def to_python(self, value):
        if isinstance(value, ExternalClass):
            return value

        if value is None:
            return value

        return ExternalClass(value)

    def get_prep_value(self, value):
        if value is None:
            return value

        if isinstance(value, ExternalClass):
            return value.to_string()

        return value

该字段的行为与预期一致。但是,我仍然坚持使用文档的这一部分:deconstruct()函数。

特别是,我不明白的是:

  • 解构功能的目的究竟是什么?
  • 即使没有它,我的领域如何运作得很好(即使我修改了init参数)?
  • Django如何以及​​何时调用解构函数?

我不想盲目地复制粘贴我不理解的代码,但文档不清楚。

1 个答案:

答案 0 :(得分:17)

deconstruct()方法用于帮助执行无法由系统自动处理的模型迁移。让我们来看看解构将被调用的场景。

假设我们有一些模型,我们为它添加了一个自定义字段。我们尝试使用python manage.py makemigrations进行迁移。

我们遇到以下错误:

ValueError: Cannot serialize: Foo
There are some values Django cannot serialize into migration files.

事实证明,已经向Django项目提交了a related ticket,让我们看一下。

ticket-issue

其中一位核心开发人员回应说这是预期的行为,因为我们的字段包含一个可调用的。

ticket-resolution

所以,我们错过了文档中的内容。存储了可调用的值,并且由于某种原因无法自动迁移。我们能做什么?

嗯,除了告诉我们ValueError之外,manage.py还为我们提供了一个有用的文档链接:

docs-link

在该页面上,向下滚动一下,直到我们进入有关serializing values的部分。

  

Django可以序列化以下内容:

     
      
  • ...
  •   
  • 使用自定义deconstruct()方法的任何内容(见下文)
  •   
  • ...
  •   

好吧,让我们see below

  

你可以让Django通过给出来序列化你自己的自定义类实例   类是一个deconstruct()方法。它不需要任何参数,而且应该   返回三个元组的元组(path,args,kwargs):

     
      
  • 路径应该是类的Python路径,带有类名   作为最后一部分包含在内(例如,myapp.custom_things.MyClass)。   如果您的课程在模块的顶层不可用,则不是   序列化。
  •   
  • args 应该是要传递给的位置参数列表   您的班级' init 方法。此列表中的所有内容本身都应该是   序列化。
  •   
  • kwargs 应该是传递给关键字参数的字典   您的班级' init 方法。每个价值本身都应该是   序列化的。
  •   

请注意,deconstruct()方法与__eq__()密切配合,如文档中所述:

  

为了防止每次运行makemigrations时都创建新的迁移,您还应该向装饰的类添加 __ eq __()方法。 Django的迁移框架将调用此函数来检测状态之间的变化。

在我的情况下,错误是在一个不应该被调用的值之后添加括号,但在许多情况下,您将要实现迁移的解构方法。 (这是另一个有useful link的例子。)