覆盖实例属性

0 投票
2 回答
665 浏览
提问于 2025-04-18 15:02

views.py 文件中,我有:

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

计算机对象有一个叫做 projects 的字段,它是一个 ManyRelatedManager

调用

my_projects = my_computer.projects.all()

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

我想要实现的是把 my_computer.projects 的值设置为上面提到的项目列表,而不是 ManyRelatedManager

我尝试过:

my_computer.projects = my_projects

但这并没有成功,虽然也没有报错。my_computer.projects 的值仍然是 ManyRelatedManager

2 个回答

1

你不能这样做。最好的办法就是换一个属性名称。

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

Manager 对象实现了 __set__ 方法,这意味着它们像描述符一样工作。

这就意味着你不能通过赋值来改变这个对象(只要它是另一个对象的属性 - __set__ 只会在父对象的 __setattr__ 上被调用 - 这里的父对象是指组合关系,而不是继承关系)。

如果你给一个管理器赋值,必须是一个类似列表的(实际上是可迭代的)值,并且这个可迭代的值必须能产生预期类型的模型。不过这意味着:

  1. 当你查询 my_computer.projects 时,你会再次得到一个管理器对象,里面包含你之前赋值的对象。
  2. 当你保存对象 my_computer 时,只有指定的对象会属于这个关系 - 之前在关系中的对象将不再与当前对象相关联。

你可能遇到这个问题的原因有三种情况:

  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=(你必须为同一模型的多个关系中的至少一个显式设置 related_name)

撰写回答