我一直在为如何在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_attr2
或MyModel
时,我要实现以下行为:
如果外键为空,只需将值保存在MyModel
上。
如果外键不为null,并且该值不同于与外键链接的记录上共享的值,则将该值保存在MyModel
上。
否则,将值留空。
然后,当我从MyModel
上的任何一个共享属性中检索值时,我希望它执行以下操作:
如果外键为空,请返回MyModel
上的属性值。
如果外键不为空,并且MyModel
上的值与MyModelGroup
上的值不同,请返回MyModel
上的值。
如果外键不为空,并且MyModel
上的值为空,则返回MyModelGroup
上的值。
目标是允许一堆MyModel
从MyModelGroup
继承值,并可能通过在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
这两种方法都不符合我的预期。你们以前有没有实现过类似的东西?
答案 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)