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)
2 个回答
1
正如你在问题中提到的,你的解决方案的问题在于,它为每个对象生成一个SQL查询,而不是使用一个SQL in = (id1, id2)
查询。代理模型不能包含额外的数据库字段,所以不需要额外的SQL查询。
相反,你可以在 SuperConnect.__init__
中将一个SuperConnect对象转换为合适的类型,使用 __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对象时,正确的类型就已经设置好了。
0
把所有的逻辑放在一个类里怎么样?可以像这样:
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
字段,这样你应该能够做大部分(如果不是全部的话)你可以用不同的代理类做的事情。
如果这种方法不能解决你特定的需求,请再详细说明一下。