Django 从模型字段访问模型实例

Django 从模型字段访问模型实例,django,django-models,Django,Django Models,我希望Django自定义模型字段在模型实例上设置一个属性 我确信它不是这样工作的,但这里有一个例子: class MyField(models.Field): __metaclass__ = models.SubfieldBase def __init__(self, *args, **kwargs): super(MyField, self).__init__(*args, **kwargs) model_instance = ????

我希望Django自定义模型字段在模型实例上设置一个属性

我确信它不是这样工作的,但这里有一个例子:

class MyField(models.Field):
    __metaclass__ = models.SubfieldBase
    def __init__(self, *args, **kwargs):
        super(MyField, self).__init__(*args, **kwargs)
        model_instance = ????
        setattr(model_instance, "extra_attribute", "It's working!")

class MyModel(models.Model):
    my_field = MyField()

model_instance = MyModel.objects.get(pk=123)
print model_instance.extra_attribute # output: "It's working!"
Django的ForeignKey模型字段也在做类似的事情,所以这是可能的:p 我认为ForeignKey字段使用的是贡献给类的方法。

怎么样

model_instance = SomeExtraModel.objects.get(pk=1456)
用有意义的东西替换1456怎么样

model_instance = SomeExtraModel.objects.get(pk=1456)

当Django处理模型类而不是模型实例时,会调用init,用有意义的东西替换1456。因此,您可以将该属性添加到模型类中,例如使用“add_to_Class”。要将属性添加到实例中,您应该覆盖实例的init,但我认为这不是您的情况。

init是在Django处理模型类而不是模型实例时调用的。因此,您可以将该属性添加到模型类中,例如使用“add_to_Class”。要向实例添加属性,您应该覆盖实例的init,但我认为这不是您的情况。

您没有从Field对象内部访问模型实例的权限,抱歉。Django的ForeignKey通过具有单独的name和attname字段来实现foo_id,但是foo_id=123的实际设置与所有其他模型字段相同,不与字段类交互

从概念上讲,你试图做的是一个坏主意——远距离行动。如果添加一个特定字段可能会导致不相关的模型功能中出现错误,比如说,如果另一个字段所期望的属性被覆盖,该怎么办?至少可以说,调试是困难的。我不知道您的基本目标是什么,但它可能应该在模型代码中完成,而不是在字段类中完成

下面是一个模型字段,它可以满足您的需要:


这实际上相当古老,可能是1.0之前的版本,现在不记得了,我不得不把它掸掉一点——我不确定它是否还能工作。但这绝对是可行的,希望这能给您一个想法。

您无法从字段对象内部访问模型实例,抱歉。Django的ForeignKey通过具有单独的name和attname字段来实现foo_id,但是foo_id=123的实际设置与所有其他模型字段相同,不与字段类交互

从概念上讲,你试图做的是一个坏主意——远距离行动。如果添加一个特定字段可能会导致不相关的模型功能中出现错误,比如说,如果另一个字段所期望的属性被覆盖,该怎么办?至少可以说,调试是困难的。我不知道您的基本目标是什么,但它可能应该在模型代码中完成,而不是在字段类中完成

下面是一个模型字段,它可以满足您的需要:


这实际上相当古老,可能是1.0之前的版本,现在不记得了,我不得不把它掸掉一点——我不确定它是否还能工作。但是它确实是可行的,希望这能给你一个想法。

你可以创建一个特殊的代理类来替换这个字段。获取或设置字段值时,可以使用“obj”属性访问模型实例。请参见此示例:

class ObjectField(models.PositiveSmallIntegerField):
    class ObjectProxy:
        def __init__(self, field):
            self.field = field

        def __get__(self, obj, model):
            if obj is None:
                return self.field  # this is required for initializing model field

            value = obj.__dict__[self.field.name]  # get actual field value
            # ... here you can do something with value and model instance ("obj")

            return value

        def __set__(self, obj, value):
            # same here
            obj.__dict__[self.field.name] = value

    def contribute_to_class(self, cls, name):
        super().contribute_to_class(cls, name)
        # set up our proxy instead of usual field
        setattr(cls, name, ObjectField.ObjectProxy(self))

您可以创建一个特殊的代理类来替换该字段。获取或设置字段值时,可以使用“obj”属性访问模型实例。请参见此示例:

class ObjectField(models.PositiveSmallIntegerField):
    class ObjectProxy:
        def __init__(self, field):
            self.field = field

        def __get__(self, obj, model):
            if obj is None:
                return self.field  # this is required for initializing model field

            value = obj.__dict__[self.field.name]  # get actual field value
            # ... here you can do something with value and model instance ("obj")

            return value

        def __set__(self, obj, value):
            # same here
            obj.__dict__[self.field.name] = value

    def contribute_to_class(self, cls, name):
        super().contribute_to_class(cls, name)
        # set up our proxy instead of usual field
        setattr(cls, name, ObjectField.ObjectProxy(self))

不,init被称为对象构造的最后一步。@Marcin:谢谢,我可能误解了实际的流程。你能发布一些关于它的文档吗?哇,玛辛,你是个混蛋。他显然是在谈论Django ORM代码路径,这不是一个微不足道的问题。作为记录,Don,您有一个正确的字段。uuu init_uuu在模块导入时被调用,在模型实例化过程中从未被调用。@AdamKG:读者应该在第一句话中插入单词Field和model,这一点并不明显。另外,确切地说,Field.\uuuu init\uuuuuu在类创建时被调用,这些字段属性在类的主体中声明,这可能晚于模块导入时间;如果你设法破解了一个工作的django模型,该模型稍后会创建字段,那么这种情况就会发生。不,init被称为对象构造的最后一步。@Marcin:谢谢,我可能误解了实际的流程。你能发布一些关于它的文档吗?哇,玛辛,你是个混蛋。他显然是在谈论Django ORM代码路径,这不是一个微不足道的问题。作为记录,Don,您有一个正确的字段。uuu init_uuu在模块导入时被调用,在模型实例化过程中从未被调用。@AdamKG:读者应该在第一句话中插入单词Field和model,这一点并不明显。另外,确切地说,Field.\uuuu init\uuuuuu在类创建时被调用,这些字段属性在类的主体中声明,这可能晚于模块导入时间;如果你设法破解了一个可以工作的django模型,以后再创建字段,这种情况就会发生
创建一个字段,该字段支持与任何模型(如GenericForeignKey)的关系,但只在一个字段中。它将%d.%d%model_type,instance.pk保存到charfield。该字段的attname将为%s\u guid%name=model\u instance.my\u field\u guid。当model_instance.my_字段被调用时,我想点击数据库并为相关实例提供服务,就像Foreignkey所做的一样。谢谢哦,那很简单。我以为你的意思是设置任意的其他字段。我将用我所看到的ModelField的一个例子来更新。当创建一个模型实例时,to_python方法会对所有字段运行,对吗?我只想在调用此特定字段时将charfield值转换为正确类型的对象。就像ForeignKey field一样。我认为这就是ForeignKey领域的诀窍所在:但我一直无法复制它。谢谢,我正在尝试创建一个字段,该字段支持与任何模型(如GenericForeignKey)的关系,但只在一个字段中。它将%d.%d%model_type,instance.pk保存到charfield。该字段的attname将为%s\u guid%name=model\u instance.my\u field\u guid。当model_instance.my_字段被调用时,我想点击数据库并为相关实例提供服务,就像Foreignkey所做的一样。谢谢哦,那很简单。我以为你的意思是设置任意的其他字段。我将用我所看到的ModelField的一个例子来更新。当创建一个模型实例时,to_python方法会对所有字段运行,对吗?我只想在调用此特定字段时将charfield值转换为正确类型的对象。就像ForeignKey field一样。我认为这就是ForeignKey领域的诀窍所在:但我一直无法复制它。谢谢