以下是models.py
:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
def __init__(self, *args, **kwargs):
super(Base, self).__init__(*args, **kwargs)
setattr(self, 'name', json.loads(self.json_dump)['name'])
class Meta:
abstract = True
class Child(Parent):
magnitude = models.IntegerField()
在我的admin.py
中,我想为子管理员配置显示name
属性,所以我有以下内容:
class ChildAdmin(admin.ModelAdmin):
model = Child
def get_list_display(self, request):
return ('id', 'name', 'magnitude')
admin.site.register(Child, ChildAdmin)
我必须从list_display
方法动态生成get_list_display
,否则Django会在启动时抛出错误,抱怨name
模型中未定义Child
。但是,在运行时,name
应该可用,因为只要从数据库中实例化对象,就会在__init__
方法中设置它。
但是,当我尝试加载管理页面时,我收到错误:
Unable to lookup 'name' on Child or ChildAdmin
是什么给出了?
答案 0 :(得分:6)
<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
,它不存在。
我们要查看的错误部分是:
...这不是可调用
不。它不是可调用的,它是一个属性。
...&#39; ChildAdmin&#39; 的属性,
不。它不是ChildAdmin
类的属性。
...或者&#39; app.Child&#39; 上的属性或方法。
这是绊倒你的部分。 &#34;是什么给#34;它不是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
类可以使用该属性。或者,您可以创建名为@property
的函数定义,而不是使用get_name
装饰器。我发现第一个更简单。
此方法的警告是它不会在运行时保存名称。如果你想这样做,你可能想要考虑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',
)
]
正如您所看到的,我在运行的代码中添加了注释,以帮助您了解正在发生的事情。你是{1}}的实例确实有名,你是对的,但这并不是Django所寻求的。它正在寻找一个类属性,而不是实例属性。
所以,你可以解决这个问题的另一种方式(你也不会这样),这样做是:
Child
这很有效。我刚试过它。 Django会在类上找到属性。
答案 1 :(得分:0)
正如doc中所述,更改Parent
模型,如下所示:
class Parent(models.Model):
id = models.CharField(max_length=14, primary_key=True)
json_dump = models.TextField(null=False)
def name(self):
return json.loads(self.json_dump)['name']
class Meta:
abstract = True
将显示name
属性。