带有默认字段的Django模型序列化问题

Posted

技术标签:

【中文标题】带有默认字段的Django模型序列化问题【英文标题】:Django model serialization problem with default fields 【发布时间】:2019-04-08 19:05:43 【问题描述】:

在我的应用模型内部,我使用 IntegerRangeField 字段:

from django.db import models
from django.contrib.postgres.fields import IntegerRangeField
from django.contrib.postgres.validators import RangeMinValueValidator, RangeMaxValueValidator
from psycopg2.extras import NumericRange


class MyModel(models.Model):
    ...

    field = IntegerRangeField(default=NumericRange(400, 600), validators=[
        RangeMinValueValidator(1),
        RangeMaxValueValidator(1000)
    ])
    ...

default”属性仅在管理面板 UI 中使用,在其他任何地方都不需要。

如果我在迁移后添加它们,它们会顺利运行。但是,如果我在运行 makemigrations 之前添加它们,我会收到以下消息:

ValueError: Cannot serialize: NumericRange(400, 600, '[)') 有 一些值 Django 无法序列化到迁移文件中。

我什至不希望将默认值保存到我的 PostgreSQL 数据库中,我只想在每次运行 makemigrations 时都不必删除并恢复它们。

有什么想法吗?

(不起作用:具有“lower”和“higher”属性、单个整数、字符串、元组的自定义对象)

Python:3.6.6,Django:2.1.2,PostgreSQL:11.0

【问题讨论】:

【参考方案1】:

尝试将默认值计算移到单独的函数中:

def get_default_range():
    return NumericRange(400, 600)

class MyModel(models.Model):
    field = IntegerRangeField(default=get_default_range, validators=[
        RangeMinValueValidator(1),
        RangeMaxValueValidator(1000)
    ])

在这种情况下成功生成迁移:

   operations = [
       migrations.AddField(
            model_name='comment',
            name='field',
            field=django.contrib.postgres.fields.ranges.IntegerRangeField(
                default=play.models.get_default_range,
                validators=[django.contrib.postgres.validators.RangeMinValueValidator(1),
                            django.contrib.postgres.validators.RangeMaxValueValidator(1000)]),
        ),
    ]

【讨论】:

非常感谢!没错,创建了迁移,但它只是将问题转移到其他地方:当您尝试访问它时,您会得到 AttributeError: 'range' object has no attribute 'lower' @ozz 好的,我知道这不起作用。简单的元组怎么样,比如default=(400, 600)在这种情况下你有什么错误? @ozz 正如我在文档中看到的,只有在用于过滤模型 docs.djangoproject.com/en/1.8/ref/contrib/postgres/fields/… 时,您才需要使用 psycopg2.extras.NumericRange 但将默认值定义为元组通常是可以的 我得到同样的错误:AttributeError: 'tuple' object has no attribute 'lower'。我已经浏览了文档,没有解决方案 @ozz 你什么时候有这个错误?当运行makemigrations 命令或...?你能发布完整的堆栈跟踪吗【参考方案2】:

我能够使用范围的字符串表示来解决这个问题:

IntegerRangeField(default='[400, 600]')

django==3.0.5 psycopg2==2.8.5

【讨论】:

【参考方案3】:

编辑我应该指出,最初的问题是 2 岁,但至少在 django 3.1 中,它们是一个序列化程序,您必须单独注册。

你需要注册django提供的序列化器。

from psycopg2.extras import NumericRange
from django.contrib.postgres.serializers import RangeSerializer
from django.db.migrations.writer import MigrationWriter

MigrationWriter.register_serializer(NumericRange, RangeSerializer)

这篇文章不在文档中,但是您可以按照您的期望添加默认值:

class AgeDivision(models.Model):
    name = models.CharField(max_length=50, unique=True)
    age_range = fields.IntegerRangeField(
        unique=True, blank=True, default=NumericRange(None, None))

至于放在哪里,它只需要放在任何只加载一次的模块旁边。文档没有指定将自定义序列化程序放在哪里(至少我能找到),但我会说将它们放在需要序列化程序的任何应用程序的 migrations/__init__.py 文件中。这是关于迁移序列化的文档:https://docs.djangoproject.com/en/3.1/topics/migrations/#custom-serializers

【讨论】:

以上是关于带有默认字段的Django模型序列化问题的主要内容,如果未能解决你的问题,请参考以下文章

Django REST Framework 序列化程序字段必需=false

Django:有没有办法序列化模型字段而不是模型?

没有唯一一起验证的 Django Rest Framework 模型序列化程序

Django 仅序列化一个字段而不是相关字段中的整个模型(只读)

我可以将单个 Django 模型字段拆分为多个 Django Rest Framework 序列化器字段吗?

Django序列化来自不同模型的字段