如何在不修改父类时排除子类的django-simple-history HistoricalRecords
问题描述
需要在不修改父类BaseModel的前提下,让子类Manager不继承django-simple-history的HistoricalRecords。现有代码中BaseModel包含history = HistoricalRecords(inherit=True),尝试在Manager类中设置history=None以及在__init__方法中清理字段,但执行makemigration时仍会为Manager生成历史记录。由于BaseModel和CommonWithExtraFieldsWithoutVersioning被广泛使用无法修改,寻求解决方案。
原代码:
from simple_history.models import HistoricalRecords class BaseModel(models.Model): id = models.UUIDField(...some args...) created_at = models.DateTimeField(...some args...) created_by = models.ForeignKey(...some args...) history = HistoricalRecords(inherit=True) class Meta: abstract = True default_permissions = Constants.STANDARD_ACTIONS def save(self, suppress_modified=False, from_publish=False, **kwargs): super(BaseModel, self).save(**kwargs) class CommonWithExtraFieldsWithoutVersioning(BaseModel, CommonWithoutVersioning, models.Model): class Meta(CommonWithoutVersioning.Meta): abstract = True class Manager(CommonWithExtraFieldsWithoutVersioning): from_branch = models.CharField(...some args...) to_branch = models.CharField(...some args...) from_version = models.IntegerField(...some args...) to_version = models.IntegerField(...some args...) history = None # 无效 def __init__(self, *args, **kwargs): super(DSLJourneyMergeHistory, self).__init__(*args, **kwargs) self.clean_fields('history') # 无效
解决方案
直接设置history=None无法生效,因为django-simple-history的inherit=True会让子类自动继承历史字段,且makemigrations会检测到父类的字段定义。可以通过自定义元类在Manager类创建时彻底移除history字段,避免生成历史表:
from django.db import models from simple_history.models import HistoricalRecords # 自定义元类:移除继承的history字段 class DisableHistoryMeta(models.base.ModelBase): def __new__(cls, name, bases, attrs): # 先移除类属性中的history if 'history' in attrs: del attrs['history'] # 创建模型类 model_class = super().__new__(cls, name, bases, attrs) # 从模型的元数据中移除history字段 model_class._meta.fields = [field for field in model_class._meta.fields if field.name != 'history'] model_class._meta.local_fields = [field for field in model_class._meta.local_fields if field.name != 'history'] # 删除类上的history属性(如果存在) if hasattr(model_class, 'history'): delattr(model_class, 'history') return model_class # 修改Manager类,使用自定义元类 class Manager(CommonWithExtraFieldsWithoutVersioning, metaclass=DisableHistoryMeta): from_branch = models.CharField(...some args...) to_branch = models.CharField(...some args...) from_version = models.IntegerField(...some args...) to_version = models.IntegerField(...some args...) # 不需要再设置history=None或在__init__中清理
原理说明
- 元类会在模型类创建的早期阶段介入,直接移除
history相关的属性和字段定义,让django的迁移系统无法检测到该字段。 - 这种方式不会影响其他继承
BaseModel的子类,仅对使用该元类的Manager类生效。
内容的提问来源于stack exchange,提问作者Shubham Srivastava
相关产品推荐
相关产品推荐

