Django代理模型和外键
如何让entry.category成为CategoryProxy的实例?具体代码如下:
class Category(models.Model): pass
class Entry(models.Model):
category = models.ForeignKey(Category)
class EntryProxy(Entry):
class Meta:
proxy = True
class CategoryProxy(Category):
class Meta:
proxy = True
entry = EntryProxy.objects.get(pk=1)
entry.category # !!! I want CategoryProxy instance here
把Category转换成CategoryProxy也是可以的,不过我对ORM的内部机制不太熟悉,所以不知道怎么正确地复制内部状态……
编辑: 原因是:我在CategoryProxy里添加了一个方法,想要使用它:
EntryProxy.objects.get(pk=1).category.method_at_category_proxy()
编辑 2: 目前我这样实现的:
EntryProxy._meta.get_field_by_name('category')[0].rel.to = CategoryProxy
但是看起来很糟糕……
7 个回答
2
目前的解决方案(包括被接受的那个)在Django 2.0上都不管用。
基于Matt Schinckel关于重写代理模型关系的研究,这里有一个适用于Django 2.0和2.1的解决方案。
9
这是一个关于Django的公开问题:#10961(允许用户在使用ForeignKey字段的代理模型上覆盖正向和反向关系)
你可以通过在定义代理模型后重置相关字段来解决这个问题:
EntryProxy.add_to_class('category', CategoryProxy)
15
要在不访问数据库的情况下,从模型类切换到代理类:
class EntryProxy(Entry):
@property
def category(self):
new_inst = EntryProxy()
new_inst.__dict__ = super(EntryProxy, self).category.__dict__
return new_inst
补充说明:上面的代码在django 1.4上似乎不太好使。
从django 1.4开始,我手动获取所有值字段,像这样:
class EntryProxy(Entry):
@property
def category(self):
category = super(EntryProxy, self).category
new_inst = EntryProxy()
for attr in [f.attname for f in category.__class__._meta.fields] + ['_state']:
setattr(new_inst, attr, getattr(category, attr))
return new_inst
要在不访问数据库的情况下,从查询集切换到子代理类:
class CategoryProxy(Category):
@property
def entry_set(self):
qs = super(CategoryProxy, self).entry_set
qs.model = EntryProxy
return qs