尝试保留历史数据时外键on_delete的正确设置

时间:2018-09-19 13:58:46

标签: django django-models foreign-keys

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

假设我有模型CarEngineType。我希望Car具有EngineType作为外键来填充汽车引擎。那很容易。

我的问题是这样的:可以说EngineType仅应显示正在生产的活动实例,因此,如果它们停止从1970年代开始生产3.5 liter 120 hp引擎,我就不希望这样做在创建新车时会出现在选择的发动机类型上。另一部分是,我希望所有记录都保留在汽车数据库中以进行历史报告。所以发生了什么事,我尝试删除上述引擎,如果有的话

on_delete=CASCADE

这没做我想要的,因为我丢失了历史数据。如果有

on_delete=PROTECT

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

您如何处理?

1 个答案:

答案 0 :(得分: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)

此代码将确保通过此表格仅可将活动引擎分配给该车。

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