在Django/Python中向继承列表插入额外项

0 投票
2 回答
1961 浏览
提问于 2025-04-16 04:38

我在我的Django应用中使用了一些子类,并且我想把这个逻辑继续应用到我的管理界面上。

现在,我有这样的管理定义:

class StellarObjectAdmin(admin.ModelAdmin):
  list_display = ('title','created_at','created_by','updated_at','updated_by)

我有一个叫做Planet的类,它是StellarObject的子类,并且多了一个字段。我想把这个字段添加到列表显示中(而不是完全替换掉StellarObject的显示)。

如果我尝试这样做:

class PlanetAdmin(StellarObjectAdmin):
  list_display.insert(1,'size')

我就会遇到以下错误:

name 'list_display' is not defined

我承认,我对Python和继承的概念还很陌生,所以我肯定有一些简单的地方没有理解。

谢谢!

2 个回答

1

大卫说得很对。另外,值得注意的是,如果你想在类里面引用某个变量,你需要用上 'self.' 这个前缀。

举个例子:

Class A:
   mylist = [1,2,3]

   def display_list(self):
      for i in self.mylist:
           print i
2

你需要使用:

StellarObjectAdmin.list_display.insert(1, 'size')

另外,你需要把 list_display 从一个 tuple(这是一种不可变的类型)改成一个 list。比如说:list_display = [ ... ]

最后,你可能会对接下来发生的事情感到惊讶:当你插入这个项目时,你实际上是在改变 StellarObjectAdmin 上的列表。你可能想要做的是:

list_display = list(StellarObjectAdmin.list_display) # copy the list
list_display.insert(1, 'size')

这样会为你的 PlanetAdmin 类创建一个新的列表副本。

之所以会这样,是因为 Python 的继承方式。简单来说,Python 不会自动把名字放进命名空间(比如,有些语言会在方法中自动注入一个神奇的 this “变量”,而 Python 要求你明确地把相应的内容 — self — 作为方法的第一个参数),而且因为 class 只是另一个命名空间,所以没有任何东西(比如它的父类中的值)会被自动注入。

当你有一个类 B,它继承自另一个类 A,如果你想在 B 上查找一个属性 B.foo,它会先检查 foo 是否在 B 的命名空间里,如果没有,就会去检查 A 的命名空间,依此类推。

希望这样说清楚了……如果不清楚,我可以再解释一下(或者试着找相关的文档)。

撰写回答