【问题标题】:Django model serialization problem with default fields带有默认字段的Django模型序列化问题
【发布时间】: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

【问题讨论】:

    标签: python django postgresql django-models django-admin


    【解决方案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

      【讨论】:

        猜你喜欢
        • 2017-11-10
        • 1970-01-01
        • 2011-06-04
        • 2010-10-19
        • 1970-01-01
        • 1970-01-01
        • 2017-01-28
        • 1970-01-01
        相关资源
        最近更新 更多