透明地继承Django模型属性

时间:2018-06-20 12:58:22

标签: python django

我一直在为如何在Django 1.7上实现以下功能而绞尽脑汁。我有两个Django模型。一个字段上的某些字段在另一个字段上重复。它们与外键相关,就像这样。

class MyModelGroup(models.Model):
    name = models.CharField(max_length=128)
    shared_attr1 = models.NullBooleanField()
    shared_attr2 = models.CharField(max_length=512, null=True, blank=True)

class MyModel(models.Model):
    group = models.ForeignKey(MyModelGroup, null=True, blank=True)
    name = models.CharField(max_length=128)
    shared_attr1 = models.NullBooleanField()
    shared_attr2 = models.CharField(max_length=512, null=True, blank=True)

MyModel可能与MyModelGroup记录相关。在shared_attr1上更改shared_attr2MyModel时,我要实现以下行为:

  1. 如果外键为空,只需将值保存在MyModel上。

  2. 如果外键不为null,并且该值不同于与外键链接的记录上共享的值,则将该值保存在MyModel上。

  3. 否则,将值留空。

然后,当我从MyModel上的任何一个共享属性中检索值时,我希望它执行以下操作:

  1. 如果外键为空,请返回MyModel上的属性值。

  2. 如果外键不为空,并且MyModel上的值与MyModelGroup上的值不同,请返回MyModel上的值。

    < / li>
  3. 如果外键不为空,并且MyModel上的值为空,则返回MyModelGroup上的值。

目标是允许一堆MyModelMyModelGroup继承值,并可能通过在MyModel上存储不同的值来覆盖这些值。

我尝试在__getattr__上实现__setattr__MyModel来透明地检查外键是否存在,并在适当时获取并设置值,但是Django做了很多工作魔法使事情变得困难。

我也尝试使用计算字段来实现它,就像这样:

@property
def shared_attr1(self):
    # renamed model field to _shared_attr1
    if self.group and self._shared_attr1 is None:
        return self.group._shared_attr1

    return self._shared_attr1

@shared_attr1.setter
def shared_attr1(self, new_value):
    if self.group is None or new_value != self.group._shared_attr1:
        self._shared_atttr1 = new_value

这两种方法都不符合我的预期。你们以前有没有实现过类似的东西?

2 个答案:

答案 0 :(得分:1)

从我的角度来看,具有这种功能的最好方法是创建Custom Django Field。保存前使用pre_save调整值。

除了为该字段定义getter之外,setter使用pre_save方法在将值传递到数据库之前将其转换。

有关灵感,请参见You can see django.db.fields

答案 1 :(得分:0)

我不会太花哨了。为什么不对'MyModel'使用非常简单的方法来返回适当的值:

def get_shared_attr1(self):
    if self.shared_attr1:
        return self.shared_attr1
    if self.group:
        return self.group.shared_attr1
    return None

并在save中处理适当状态的维护:

def save(self, *args, **kwargs):
    if self.group and self.shared_attr1 == self.group.shared_attr1:
        self.shared_attr1 = ''        
    super(MyModel, self).save(*args, **kwargs)

您将不得不处理在组的save中更改该组的属性的情况:

def save(self, *args, **kwargs):
    self.mymodel_set.filter(shared_attr1=self.shared_attr1).update(shared_attr1='')        
    super(MyModelGroup, self).save(*args, **kwargs)