【问题标题】:Django simple history inheritance getting from parent to child historyDjango简单历史继承从父到子历史
【发布时间】:2019-12-25 09:57:01
【问题描述】:

我正在尝试使用django-simple-history 来保持对象的状态。

假设我有以下内容:

class Parent(models.Model):
    fields...
    history = HistoricalRecords(inherit=True)

class Child(Parent):
    fields...

class Invoice(models.Model):
    fields...
    parent_history = models.ForeignKey("app.HistoricalParent", blank=True, null=True, on_delete=models.PROTECT, help_text="This keeps the state of the Child when Invoice is generated")
    parent =  models.ForeignKey(Parent, blank=True, null=True, on_delete=models.PROTECT) # can be removed so foreign key loop gets eliminated

如何从Invoice 到达Child

Invoice.objects.get(id=1).parent_history.child

不工作和提高

AttributeError: 'HistoricalParent' object has no attribute 'child'

这就是我从Parent 到达Child 的方式

Invoice.objects.get(id=1).parent.child

我找不到从HistoricalChildHistoricalParent 的外键。我错过了什么吗? django-simple-history 是否以其他方式工作?

【问题讨论】:

  • HistoricalParent类的定义是什么?
  • @KrazyMax 它由django-simple-history 定义,它与Parent 基本相同,加上更多的列,如change_reason, history_id, history_date and histtory_type
  • 好的。我不明白的是,您的Child 课程。你想让它继承Parent 类吗?喜欢拥有与您的Parent 类相同的字段吗?你给的名字有些不清楚。读到您,您无法从invoice 访问child 听起来很正常,因为parent_history 没有child 字段(parent_historyParent 之间是否存在混淆?
  • @KrazyMax 以及django 模型继承保留了从ChildParent 的外键,所以我有从ParentChild 的反向外键。我对django-simple-history 的期望相同,但显然HistoricalChildParent 保持相同的外键而不是HistoricalParent
  • 实际上这就是你错的地方:当孩子从父母那里继承时,父母和它的孩子之间没有自动创建任何ForeignKey。您必须为此明确定义关系。此外,如果您希望 2 个类具有共同的属性和方法,我建议创建一个抽象模型(一个 mixin),然后让您的 ParentChild 从该 mixin 继承。如果这对你来说是个好主意,我可以编辑我的答案给你看一个例子!

标签: python django django-models django-simple-history


【解决方案1】:

错误消息对我来说很清楚:没有child 属性与您的Parent 模型相关联。您无法从parent 访问child,因为它们之间没有关系(从数据库的角度来看)。从父类继承并不意味着它们之间有任何关系,只是子类会继承父类的属性和方法,仅此而已。

我不确定这是您想要做的,但可以通过反向关系访问对象父级。

例如,如果您在 ParentChild 之间有明确的链接,如下所示:

class Parent(models.Model):
    fields...
    history = HistoricalRecords(inherit=True)

class Child(models.Model):
    fields...
    parent = models.ForeignKey(Parent, blank=True, null=True, on_delete=models.PROTECT, related_name='blabla')

那么,parent 可以按如下方式访问:child.parent(不足为奇),但是由于反向关系(检查related_name 参数),孩子也可以从parent 访问:parent.blabla

希望有帮助!

【讨论】:

    【解决方案2】:

    所以让我在使用django-simple-history时打破外键关系

    所以HistoricalChild 没有得到HistoricalParent 的外键

    HistoricalChild = apps.get_model('app', 'HistoricalChild')
    HistoricalChild.objects.filter(parent_ptr_id=invoice.parent_history.id).order_by('-history_date')
    

    将返回这么多项目,这对我来说毫无用处,因为父母有它从某个日期开始的状态,但孩子来自未来

    这意味着我无法通过在某个时间点引用它的历史父级来重新创建一个完整的孩子..

    我最终使用historical_date 从某个时间重新创建Child 实例,就像这样

    parent_dict = apps.get_model('order', 'HistoricalParent').objects.filter(history_date__lte=invoice.created_date).order_by('-history_date').values().first()
    child_dict = apps.get_model('app', 'HistoricalChild').objects.filter(history_date__lte=invoice.created_date).order_by('-history_date').values().first()
    
    child_dict.update(parent_dict)
    
    for field in ['history_change_reason', 'history_id', 'history_type', 'history_date', 'history_user_id']:
        child_dict.pop(field)
    
    child_from_the_past = Child(**child_dict)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-06
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 2013-11-30
      相关资源
      最近更新 更多