Python Django代理模型和ForeignKey
如何使entry.category成为CategoryProxy的实例?有关详细信息,请参见代码:Python Django代理模型和ForeignKey,python,django,django-models,Python,Django,Django Models,如何使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 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
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
但是看起来很糟糕…在EntryProxy上定义一个属性
category
,该属性通过其id查找CategoryProxy:
class EntryProxy(Entry):
@property
def category(self):
cid = super(EntryProxy, self).category.id
return CategoryProxy.objects.get(id=cid)
class Meta:
proxy = True
要在不命中数据库的情况下从模型类切换到代理类,请执行以下操作:
class EntryProxy(Entry):
@property
def category(self):
new_inst = EntryProxy()
new_inst.__dict__ = super(EntryProxy, self).category.__dict__
return new_inst
class CategoryProxy(Category):
@property
def entry_set(self):
qs = super(CategoryProxy, self).entry_set
qs.model = EntryProxy
return qs
编辑:上面的代码片段似乎不适用于django 1.4
自django 1.4以来,我手动获取所有值字段,如下所示:
EntryProxy._meta.get_field_by_name('category')[0].rel.to = CategoryProxy
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 EntryProxy(Entry):
@property
def category(self):
new_inst = EntryProxy()
new_inst.__dict__ = super(EntryProxy, self).category.__dict__
return new_inst
class CategoryProxy(Category):
@property
def entry_set(self):
qs = super(CategoryProxy, self).entry_set
qs.model = EntryProxy
return qs
稍加修改Bernd Petersohn的回答,我们得出:
class EntryProxy(Entry):
@property
def category(self):
return CategoryProxy.objects.get(id=self.category_id)
对于数据库来说,这应该更经济。对于附加的改进,您可以在第一次调用该方法时设置私有属性(
self.\u category
),然后在所有后续时间返回该属性。这是一个开放的Django问题:
定义代理模型后,可以通过重置相关字段来解决此问题:
EntryProxy.add_to_class('category', CategoryProxy)
这个问题已经有了一个公认的答案,但我想为任何可能来搜索的人发布这个问题 您可以在运行时使用新字段修补模型,以便关系按预期工作。这里可以看到一个完整的例子-
目前的解决方案(包括公认的解决方案)都不能与Django 2.0一起使用
在Matt Schinckel的基础上,这里有一个。您为什么要这样做?我在CategoryProxy中添加了方法,并希望像EntryProxy.objects.get(pk=1.category.method_at_category_proxy()一样使用它,这意味着每次类别查找都会命中数据库!如果我们在循环呢?+1+1谢谢!你是怎么想到这个的?我很好奇你是否有一篇博文或其他东西详细解释QuerySet.model是如何工作的……第一次是在stackoverflow中找到的,第二次是在bpython shell测试中找到的。很高兴看到它有所帮助。