django异构查询集代理模型
我想弄清楚如何在Django中使用代理类。我想收到一个查询集,其中每个对象都属于公共超类的代理类,以便我可以运行具有相同名称的自定义子分类方法,而我的控制器逻辑不需要知道或关心哪种代理它正在使用的模型。我不想做的一件事是将信息存储在多个表中,因为我想要统一标识符以便于参考/管理。django异构查询集代理模型
我对django/python很新,所以我很乐意听到其他方法来完成我想要做的事情。
以下是我有:
TYPES = (
('aol','AOL'),
('yhoo','Yahoo'),
)
class SuperConnect(models.Model):
name = models.CharField(max_length=90)
type = models.CharField(max_length=45, choices = TYPES)
connection_string = models.TextField(null=True)
class ConnectAOL(SuperConnect):
class Meta:
proxy = True
def connect(self):
conn_options = self.deconstruct_constring()
# do special stuff to connect to AOL
def deconstruct_constring(self):
return pickle.loads(self.connection_string)
class ConnectYahoo(SuperConnect):
class Meta:
proxy = True
def connect(self):
conn_options = self.deconstruct_constring()
# do special stuff to connect to Yahoo
def deconstruct_constring(self):
return pickle.loads(self.connection_string)
现在我想做的事情是这样的:
connections = SuperConnect.objects.all()
for connection in connections:
connection.connect()
connection.dostuff
我环顾四周,发现一些黑客,但他们看起来有问题的,并且可能需要我去到数据库中的每个项目,以获取数据我可能已经...
有人请救我:)或者我会去用这个技巧:
class MixedQuerySet(QuerySet):
def __getitem__(self, k):
item = super(MixedQuerySet, self).__getitem__(k)
if item.atype == 'aol':
yield(ConnectAOL.objects.get(id=item.id))
elif item.atype == 'yhoo':
yield(ConnectYahoo.objects.get(id=item.id))
else:
raise NotImplementedError
def __iter__(self):
for item in super(MixedQuerySet, self).__iter__():
if item.atype == 'aol':
yield(ConnectAOL.objects.get(id=item.id))
elif item.atype == 'yhoo':
yield(ConnectYahoo.objects.get(id=item.id))
else:
raise NotImplementedError
class MixManager(models.Manager):
def get_query_set(self):
return MixedQuerySet(self.model)
TYPES = (
('aol','AOL'),
('yhoo','Yahoo'),
)
class SuperConnect(models.Model):
name = models.CharField(max_length=90)
atype = models.CharField(max_length=45, choices = TYPES)
connection_string = models.TextField(null=True)
objects = MixManager()
class ConnectAOL(SuperConnect):
class Meta:
proxy = True
def connect(self):
conn_options = self.deconstruct_constring()
# do special stuff to connect to AOL
def deconstruct_constring(self):
return pickle.loads(self.connection_string)
class ConnectYahoo(SuperConnect):
class Meta:
proxy = True
def connect(self):
conn_options = self.deconstruct_constring()
# do special stuff to connect to Yahoo
def deconstruct_constring(self):
return pickle.loads(self.connection_string)
如何把所有的逻辑放在一个类中。事情是这样的:
def connect(self):
return getattr(self, "connect_%s" % self.type)()
def connect_aol(self):
pass # AOL stuff
def connect_yahoo(self):
pass # Yahoo! stuff
到底你有你的type
场,你应该能够做到大部分(如果不是全部)的东西,你可以用单独的代理类做。
如果这种方法没有解决您的具体使用案例,请澄清。
穆胡克,谢谢!这会起作用,我只是想知道是否会有更优雅的OOP解决方案......我对每个代理类都有不同的做法,我希望能够轻松添加新的代码,而不会剽窃同一班。 – 2010-10-12 01:35:43
你可以很容易地将'connect_ *'方法移动到你的代理类,它就可以工作。这里最主要的是Django ORM并不是真正面向对象的。它支持子类化,但不支持多态。我会放弃'obj .__ class __.__ name__ =='Connect'+ obj.type'约束。 – muhuk 2010-10-12 03:42:18
好吧..我想我会和我的黑客一起去。 :) 有用。我只需重写QuerySet的get方法以及......干杯。 – 2010-10-13 04:43:21
正如你在你的问题中提到的那样,你的解决方案的问题是它会为每个对象生成一个SQL查询,而不是使用一个SQL in = (id1, id2)
查询。代理模型不能包含额外的数据库字段,因此不需要额外的SQL查询。
相反,你可以一个SuperConnect对象转换为相应的类型SuperConnect.__init__
,使用__class__
属性:
class SuperConnect(models.Model):
name = models.CharField(max_length=90)
type = models.CharField(max_length=45, choices = TYPES)
connection_string = models.TextField(null=True)
def __init__(self, *args, **kwargs):
super(SuperConnect, self).__init__(*args, **kwargs)
if self.type == 'aol':
self.__class__ = ConnectAOL
elif self.type == 'yahoo':
self.__class__ = ConnectYahoo
无需定制管理或查询集,正确的类型时设置SuperConnect对象被初始化。
我实现了一些适用于我的东西,并且可以轻松扩展。我有一个要点:https://gist.github.com/3087108 – bencevolta 2012-07-11 01:00:12