覆盖实例属性

时间:2014-07-28 13:03:40

标签: python django class models manyrelatedmanager

views.py我有:

my_computer = Computer.objects.get(pk=some_value)

计算机对象有一个名为“ManyRelatedManager项目”的字段。

调用

my_projects = my_computer.projects.all()

会将my_projects的值设置为三个项目对象的列表。

我尝试实现的目的是将my_computer.projects的值设置为上述项目列表而不是ManyRelatedManager

我试过了:

my_computer.projects = my_projects

但这并不起作用,尽管它也没有引起错误。 my_computer.projects的值仍为ManyRelatedManager

2 个答案:

答案 0 :(得分:1)

你不能这样做。最好的办法是简单地使用另一个属性名称。

my_computer.related_projects = list(my_computer.projects.all())

答案 1 :(得分:1)

Manager个对象实现__set__ - 它们表现为描述符。

这意味着您无法通过分配对象来更改对象(只要另一个对象的属性 - __set__仅在父对象的__setattr__上下文中调用 - 父对象组成关系,而不是继承关系)。

如果此类可迭代值产生预期类型的​​模型,则可以将任何类似列表(实际上:可迭代)的值分配给管理器。 然而这意味着:

  1. 当您查询my_computer.projects时,您将再次获得一个管理器对象,其中包含您指定的对象。
  2. 保存对象my_computer时,只有指定的对象属于该关系 - 关系中的上一个对象将不再与当前对象相关。
  3. 您可以使用三种方案来解决此问题:

    1. 您需要保存易失性列表 - 此数据不会以任何方式存储,而是暂时使用。您必须在类中创建一个普通属性:

      class Computer(models.Model):
          #normal database fields here
      
          def __init__(self, *args, **kwargs):
              super(Computer, self).__init__(*args, **kwargs)
              #ENSURE this attribute name does not collide with any field
              #I'm assuming the Many manager name is projects.
              self.my_projects = []
      
    2. 您需要另一种完全相同的关系表示 - 这样,您需要一种舒适的方式来访问该对象,而不是调用一个奇怪的.all(),例如做[k.foo for k in mycomputer.my_projects]。你必须创建一个这样的属性:

      class Computer(models.Model):
          #Normal database fields here
          #I'm assuming the Many manager name is projects.
      
          @property
          def my_projects(self):
              #remember: my_projects is another name.
              #it CANNOT collide, so I have another
              #name - cannot use projects as name.
              return list(self.projects.all())
      
          @my_projects.setter
          def my_projects(self, value):
              #this only abstracts the name, to match
              #the getter.
              self.projects = value
      
    3. 您需要另一种关系(因此它不是易失性数据):在模型中创建另一种关系,指向相同的模式,使用相同的through(如果适用),但使用不同的相关名称=(您必须为同一模型中的至少一个多重关系显式设置related_name,来自同一模型)