一旦迁移完成,Django 2.2就无法序列化默认值

2024-09-29 21:39:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个模型,它被称为foreignkey,on_delete设置为set_DEFAULT。因此,我需要为这个模型提供一个默认项。我创建了一个静态方法,它就是这样做的

class ScheduleChoice(models.Model):
    """
    This model allows users to define crontab schedules.
    """
    label = models.CharField(max_length=256, verbose_name="Label", unique=True)
    job_schedule = models.CharField(
        max_length=256,
        default="0 0 * * *", verbose_name="Crontab"
    )

    @staticmethod
    def get_default_schedule_choice():
        """
        Because some models rely on ScheduleChoice and need a default value,
        we need to give them a default ScheduleChoice.
        """
        try:
            choice = ScheduleChoice.objects.get_or_create(
                label="Every minute",
                job_schedule="* * * * *"
            )
        except ProgrammingError:
            choice = None
        return choice

    @classmethod
    def get_choice_count(cls):
        """
        Returns how many schedule choices have been defined.
        """
        return len(cls.objects.all())

    class Meta:
        verbose_name = "schedule choice"
        verbose_name_plural = "schedule choices"

    def __str__(self):
        return self.label


class MyOtherModel(models.Model):
    """
    Model using ScheduleChoices.
    """
    job_schedule = models.ForeignKey(
        "ScheduleChoice",
        on_delete=models.SET_DEFAULT,
        default=ScheduleChoice.get_default_schedule_choice(),
        verbose_name="Schedule"
    )
    activated = models.BooleanField(default=False, verbose_name="activated")

我能够运行makemigrations,并且迁移没有问题

当我修改模型并尝试再次使用makemigrations来更新迁移文件时,问题就开始了。我得到一个错误:

ValueError: Cannot serialize: <ScheduleChoice: Every minute> There are some values Django cannot serialize into migration files. For more, see https://docs.djangoproject.com/en/2.2/topics/migrations/#migration-serializing

我试着申请,但没用。为什么Django需要序列化我的默认值?为什么只有在第一次迁移成功结束后才会这样做

我总是可以使用reset_db进行迁移,但在我的生产环境中这是不可接受的

我怎样才能解决这个问题


Tags: name模型defaultverbosegetmodelonmodels
1条回答
网友
1楼 · 发布于 2024-09-29 21:39:59

Django需要序列化您的模型,为它们生成迁移文件。因此,它还需要序列化您在模型字段上设置的大多数属性(default包括在内)。目前,您定义了一个方法并直接调用它,而不是将该方法作为默认方法提供,您的方法还返回一个带有ScheduleChoice和布尔值的元组

Django可以序列化布尔值,但不能序列化模型实例(用于迁移),因此会出现错误,更不用说元组会导致错误。您应该调用该方法,而是将该方法作为默认值传递,也不是只返回实例返回pk,理想情况下,该方法应该只是一个函数:

class ScheduleChoice(models.Model):
    """
    This model allows users to define crontab schedules.
    """
    label = models.CharField(max_length=256, verbose_name="Label", unique=True)
    job_schedule = models.CharField(
        max_length=256,
        default="0 0 * * *", verbose_name="Crontab"
    )
    
    @classmethod
    def get_choice_count(cls):
        """
        Returns how many schedule choices have been defined.
        """
        return len(cls.objects.all())

    class Meta:
        verbose_name = "schedule choice"
        verbose_name_plural = "schedule choices"

    def __str__(self):
        return self.label


def get_default_schedule_choice():
    choice, _created = ScheduleChoice.objects.get_or_create(
        label="Every minute",
        job_schedule="* * * * *"
    )
    # Why would programming error occur?
    return choice.pk # Return the pk

class MyOtherModel(models.Model):
    """
    Model using ScheduleChoices.
    """
    job_schedule = models.ForeignKey(
        "ScheduleChoice",
        on_delete=models.SET_DEFAULT,
        default=get_default_schedule_choice, # Don't call the function, only pass it
        verbose_name="Schedule"
    )
    activated = models.BooleanField(default=False, verbose_name="activated")

相关问题 更多 >

    热门问题