Django-为什么我不能从admin.py访问我的models.py中的类中的动态生成的属性? [英] Django - why can't I access dynamically-generated attributes in classes in my models.py from admin.py?

查看:191
本文介绍了Django-为什么我不能从admin.py访问我的models.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 的I​​NSTANCE确实有名称,但这不是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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆