Django-为什么我不能从admin.py访问我的models.py中的类中的动态生成的属性? [英] Django - why can't I access dynamically-generated attributes in classes in my models.py from admin.py?
问题描述
这里是 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
中,为Child配置管理员以显示 name
属性,因此我具有以下内容:
In my admin.py
I would like to configure the admin for Child to have the name
attribute displayed, so I have the following:
class ChildAdmin(admin.ModelAdmin):
model = Child
def get_list_display(self, request):
return ('id', 'name', 'magnitude')
admin.site.register(Child, ChildAdmin)
我必须从 get_list_display
方法即时生成的 list_display
,因为否则Django在启动时会抛出错误,抱怨<$ c $在 Child
模型中未定义c> name 。但是,在运行时,无论何时从对象实例化对象,在 __ init __
方法中设置的 name
应该应该可用。数据库。
I have to have list_display
generated on the fly from the get_list_display
method because otherwise Django throws an error on startup complaining that name
is not defined in the Child
model. However, when running, name
should be available as it is set in the __init__
method whenever the object is instantiated from the database.
但是,当我尝试加载管理页面时,出现错误:
However, when I try to load the admin page I get the error:
Unable to lookup 'name' on Child or ChildAdmin
有什么用?
推荐答案
<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
。
The above is more than likely the error message that you are receiving. Abstract classes do not allow you to inherit instance attributes from the abstract class like that. It is looking for self.name
on the Child class, which does not exist.
部分错误我们要看的是:
The parts of the error we want to look at is:
...这不是可调用
不是。它不是可调用的,它是一个属性。
Nope. It is not a callable, it is an attribute.
...'ChildAdmin'的属性,,
不是。它不是 ChildAdmin
类的属性。
Nope. It isn't an attribute of the ChildAdmin
class.
...或 app.Child上的属性或方法。
这是使您绊倒的部分。 所提供的是它不是 Child
类的属性或方法,而是用于 Parent
This is the part that is tripping you up. "What gives" is that it isn't an attribute or method of the Child
class, but it is for the Parent
class.
您想要做的是:
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
装饰器。我发现第一个更简单。
Doing this will make the attribute available to the Child
class from parent. Alternatively, instead of using the @property
decorator, you could create a function definition called get_name
. I find the first to be simpler.
此方法的警告是它不会在运行时保存名称。如果要执行此操作,则可能需要考虑Django的信号来执行post_save钩子以检索名称值并添加 name = models.CharField(...)
The caveat to this method is that it does not save the name at runtime. If you want to do that, you may want to consider Django's signals to do a post_save hook to retrieve the name value and add a name = models.CharField(...)
to your model.
为澄清起见,Django不支持此功能。在启动时,以下代码在list_display属性上运行检查:
For clarification, Django does not support this. On startup, the following code runs a check on the list_display property:
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
的INSTANCE确实有名称,但这不是Django正在寻找的名称。
As you can see, I have added comments to the code that is run to help you understand what is happening. You are right that the INSTANCE of Child
does have name, but that isn't what Django is looking for. It's looking for a class attribute, not instance attribute.
因此,另一种可以解决此问题的方法(您也不会这样)是: p>
So, another way you can tackle this (you won't like this, either) is by doing:
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将在类中找到该属性。
This works. I just tested it. Django will find the attribute on the class.
这篇关于Django-为什么我不能从admin.py访问我的models.py中的类中的动态生成的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!