【问题标题】:Proper setting for foreign key on_delete when trying to keep historical data尝试保留历史数据时正确设置外键 on_delete
【发布时间】:2019-02-23 17:37:49
【问题描述】:

我有一个关于在模型中使用 ForeignKey 的简短问题。

假设我有模型CarEngineType。我想要一个CarEngineType 作为外键来填充汽车的引擎。这很容易。

我的问题是这样的:假设EngineType 只应该显示生产中的活动实例,所以如果他们从 1970 年代开始停止制作 3.5 liter 120 hp 引擎,我不希望它出现在选择中创建新车时的发动机类型。另一部分是我希望所有记录都保留在汽车数据库中以进行历史报告。所以会发生什么我尝试删除上面提到的引擎,如果我有

on_delete=CASCADE

这不符合我的要求,因为我丢失了历史数据。如果我有

on_delete=PROTECT

我无法删除不需要的引擎模型。

你是怎么处理的?

【问题讨论】:

  • 所以您不想删除过时的EngineType 模型,而只是在创建新的Car 时不将它们显示在表单中,对吧?您是否想过只制作仅显示当前正在生产的EngineTypes 的自定义表单?您可以将in_production 字段添加到EngineType,然后使用它进行排序。

标签: django django-models foreign-keys


【解决方案1】:

一种选择是让您的模型像这样(基本上是您已经提出的):

class EngineType(models.Model):
    ...
    is_active = models.BooleanField(
        default=True)
    ...


class Car(models.Model):
    ...
    engine_type = models.ForeignKey(
        to=EngineType,
        on_delete=models.PROTECT)
    ...

永远不要删除任何曾经使用过的EngineType 实例。旧引擎需要标记为instance.is_active = False

然后,在您的表单和视图中,您需要检查是否只有活动的EngineType 实例可以分配给新车。有一些问题可以解决这个问题,例如this one

可能看起来像这样(假设您使用ModelForm):

class CarForm(ModelForm):
    class Meta:
        model = Car
        fields = [
            ...
            'engine_type',
            ...
        ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['engine_type'].queryset = EngineType.objects.filter(is_active=True)

此代码将确保只能通过此表单将激活的引擎分配给这辆车。

您只需要确保引擎类型不能通过其他视图或表单更改,或者也可以在其中构建相同的检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-24
    • 1970-01-01
    • 2021-04-06
    • 2019-08-07
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 2016-09-01
    相关资源
    最近更新 更多