从模型字段访问模型实例

时间:2012-03-05 11:30:05

标签: django django-models

我希望我的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字段正在使用contrib_to_class方法。

4 个答案:

答案 0 :(得分:1)

您可以创建一个将替换该字段的特殊Proxy类。获取或设置字段值时,可以使用“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))

答案 1 :(得分:0)

对不起,您无法访问Field对象内的模型实例。 Django的ForeignKey通过单独的foo_idname字段来完成attname项,但foo_id = 123的实际设置与所有其他模型字段deep in the QuerySet code,不与字段类交互。

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

这里有一个ModelField可以做你想要的事情:

https://gist.github.com/1987190

实际上已经很老了(就像1.0之前的版本,现在不记得了),不得不把它弄脏了 - 我不确定它是否仍然有用。但它绝对可行,希望这能给你一个想法。

答案 2 :(得分:-1)

当Django处理Model Class而不是Model Instance时,会调用

init 。因此,您可以将属性添加到模型类中(例如,使用'add_to_class'http://www.alrond.com/en/2008/may/03/monkey-patching-in-django/)。要将属性添加到实例,您应该覆盖实例的 init (但我认为这不是您的情况)。

答案 3 :(得分:-3)

怎么样

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

用有意义的东西取代1456