<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
。
錯誤的部分,我們想看看的是:
...which is not a callable
都能跟得上。它不是一個可調用的,它是一個屬性。
...an attribute of 'ChildAdmin',
沒有。它不是ChildAdmin
類的屬性。
...or an attribute or method on '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',
)
]
正如你所看到的,我已經添加了註釋,以運行以幫助您瞭解正在發生什麼的代碼。你是對的,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會在類中找到屬性。
非常感謝。我不想使用@property樣式,因爲我有幾十個這樣的屬性,並且想要動態地填充對象。 此外,在Parent的'__init__'方法中,'self'的類型爲'Child',可以通過在'__init__'方法中添加'print type(self)'行來驗證。所以'setattr(self,'name',json.loads(self.json_dump)['name'])'應該設置Child對象的'name'屬性。 – jononomo 2014-10-28 22:06:07
@JonCrowell我已經更新了我的答案,爲什麼Django(包含Django代碼)不喜歡你正在做的和一個替代(hacky)解決方案。查看更新答案的底部。 – 2014-10-28 22:48:13
你拯救我的一天!謝謝,它在Django 1.11 [從經理註釋的字段]工作(https://stackoverflow.com/questions/17682567/how-to-add-a-calculated-field-to-a-django-model/42491803# 42491803)課也是如此。 – Mrdev 2017-08-04 13:54:00