为了开发自定义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
参数)?我不想盲目地复制粘贴我不理解的代码,但文档不清楚。
答案 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,让我们看一下。
其中一位核心开发人员回应说这是预期的行为,因为我们的字段包含一个可调用的。
所以,我们错过了文档中的内容。存储了可调用的值,并且由于某种原因无法自动迁移。我们能做什么?
嗯,除了告诉我们ValueError
之外,manage.py
还为我们提供了一个有用的文档链接:
在该页面上,向下滚动一下,直到我们进入有关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的例子。)