带有默认字段的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 Rest Framework 模型序列化程序
Django 仅序列化一个字段而不是相关字段中的整个模型(只读)