<class 'app.admin.ChildAdmin'>: (admin.E108) The value of 'list_display[1]'
refers to 'name', which is not a callable, an attribute of 'ChildAdmin',
or an attribute or method on 'app.Child'.
以上很可能是您收到的错误消息。抽象类不允许您像这样从抽象类继承实例属性。它正在 Child 类上寻找 self.name,但它不存在。
我们要查看的错误部分是:
...不是可调用的
不。它不是可调用的,它是一个属性。
...一个'ChildAdmin'的属性,
不。它不是ChildAdmin 类的属性。
...或“app.Child”上的属性或方法。
这是让你绊倒的部分。 “给出的”是它不是Child 类的属性或方法,而是Parent 类的属性或方法。
你想做的是:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
class Meta:
abstract = True
@property
def name(self):
return json.loads(self.json_dump)['name']
class Child(Parent):
magnitude = models.IntegerField()
这样做将使该属性可用于父级的Child 类。或者,您可以创建一个名为get_name 的函数定义,而不是使用@property 装饰器。我发现第一个更简单。
此方法的注意事项是它不会在运行时保存名称。如果您想这样做,您可能需要考虑 Django 的信号来执行 post_save 挂钩以检索名称值并将 name = models.CharField(...) 添加到您的模型中。
为了澄清,Django 不支持这个。在启动时,以下代码会检查 list_display 属性:
def _check_list_display_item(self, cls, model, item, label):
"""
cls=<class 'app.admin.ChildAdmin'>
model=<class 'app.models.Child'>
item='name'
"""
# 'name' is not callable
if callable(item):
return []
# <class 'app.admin.ChildAdmin'> does not have the class attribute 'name'
elif hasattr(cls, item):
return []
# <class 'app.models.Child'> does not have the class attribute 'name'
elif hasattr(model, item):
...
else:
try:
# <class 'app.models.Child'>.Meta does not have a field called 'name'
model._meta.get_field(item)
except models.FieldDoesNotExist:
# This is where you end up.
return [
# This is a deliberate repeat of E108; there's more than one path
# required to test this condition.
checks.Error(
"The value of '%s' refers to '%s', which is not a callable, an attribute of '%s', or an attribute or method on '%s.%s'." % (
label, item, cls.__name__, model._meta.app_label, model._meta.object_name
),
hint=None,
obj=cls,
id='admin.E108',
)
]
如您所见,我已将 cmets 添加到运行的代码中,以帮助您了解正在发生的事情。你是对的,Child 的实例确实有名字,但这不是 Django 想要的。它正在寻找一个类属性,而不是实例属性。
所以,解决这个问题的另一种方法(你也不会喜欢这个)是:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
name = ''
other_item = ''
this_too = ''
and_this = ''
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
super(Parent, self).__init__(*args, **kwargs)
setattr(self, 'name', json.loads(self.json_dump)['name'])
setattr(self, 'other_item', json.loads(self.json_dump)['other_item'])
setattr(self, 'this_too', json.loads(self.json_dump)['this_too'])
setattr(self, 'and_this', json.loads(self.json_dump)['and_this'])
这行得通。我刚刚测试了它。 Django 会在类上找到属性。