首页 > 解决方案 > Django - 如何将自定义对象分配为模型属性并在该对象中获取该模型实例?

问题描述

我想从模型中分离一些逻辑并将其分组到一个属性中,就像 Django 对模型管理器(object属性)所做的那样。事实上,类似ForeignKey但没有数据库表示。

我有这样的事情:

class Remote(object):
    def __init(self, *args, **kwargs)
        self.post = ... # how to get to post instance?

    def synchronize(self):
       # this function requires Post object access
       print(self.post.name)

class Post(models.Model):
    name = models.CharField(max_length=100)
    remote = Remote()

...

for post in Post.objects.all():
    post.remote.synchronize()

问题

如何修改上述代码以访问Post对象中的Remote对象?

附加问题

是否可以确定Remote对象是从Post实例(post.remote...- 像上面一样)还是Post类(Post.remote...)调用的?

标签: pythondjango

解决方案


您在这里想要的可以使用描述符来实现。

为了让它工作,你需要__get__在你的类中定义一个方法,你希望它可以作为另一个类的属性来访问。

您的案例的一个简单示例如下所示:

class Remote:
    def __init__(self, post)
        self.post = post

    def synchronize(self):
       print(self.post.name)


class RemoteDescriptor:
    def __get__(self, obj):
        if not obj:
            return self
        remote = getattr(obj, '_remote', None)
        if not remote:
            remote = Remote(obj)
            obj._remote = remote
        return remote


class Post(models.Model):
    name = models.CharField(max_length=100)
    remote = RemoteDescriptor()

说明

在上面的代码中,每次调用Post模型的远程属性时,都会调用的__get__方法。RemoteDescriptor首先检查 obj 是确保从其他对象调用描述符,而不是直接调用。这里需要两个类 Remote 和 RemoteDescriptor 以便您能够在使用点访问的描述符中添加自定义方法(例如post.remote.calculate()

另请注意,我Remote在第一次调用和所有后续调用时将实例放置到 Post 的字典中,对象将从那里返回。

您还应该查看一篇关于 RealPython 描述符的精彩文章。


推荐阅读