2010-10-12 77 views
3

我想弄清楚如何在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) 
+1

我實現了一些適用於我的東西,並且可以輕鬆擴展。我有一個要點:https://gist.github.com/3087108 – bencevolta 2012-07-11 01:00:12

回答

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場,你應該能夠做到大部分(如果不是全部)的東西,你可以用單獨的代理類做。

如果這種方法沒有解決您的具體使用案例,請澄清。

+0

穆胡克,謝謝!這會起作用,我只是想知道是否會有更優雅的OOP解決方案......我對每個代理類都有不同的做法,我希望能夠輕鬆添加新的代碼,而不會剽竊同一班。 – 2010-10-12 01:35:43

+0

你可以很容易地將'connect_ *'方法移動到你的代理類,它就可以工作。這裏最主要的是Django ORM並不是真正面向對象的。它支持子類化,但不支持多態。我會放棄'obj .__ class __.__ name__ =='Connect'+ obj.type'約束。 – muhuk 2010-10-12 03:42:18

+0

好吧..我想我會和我的黑客一起去。 :) 有用。我只需重寫QuerySet的get方法以及......乾杯。 – 2010-10-13 04:43:21

1

正如你在你的問題中提到的那樣,你的解決方案的問題是它會爲每個對象生成一個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對象被初始化。