简体   繁体   English

django异构查询集代理模型

[英]django heterogeneous queryset proxy models

I am trying to figure out how to use proxy classes in Django. 我试图弄清楚如何在Django中使用代理类。 I want to receive a queryset where each object belongs to a proxy class of a common super class so that I can run custom sub-classed methods with the same name and my controller logic doesn't need to know or care about which kind of Proxy model it is working with. 我想收到一个查询集,其中每个对象都属于一个公共超类的代理类,这样我就可以运行具有相同名称的自定义子类方法,而我的控制器逻辑不需要知道或关心哪种代理它正在使用的模型。 One thing I don't want to do is to store the information in multiple tables because I want to have unified identifiers for easier reference/management. 我不想做的一件事是将信息存储在多个表中,因为我希望有统一的标识符以便于参考/管理。

I am pretty new to django/python so I would be happy to hear alternative ways to accomplish what I am trying to do. 我是django / python的新手,所以我很乐意听到其他方法来完成我想要做的事情。

Here is what I have: 这是我有的:

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)

Now what I want to do is this: 现在我想做的是:

connections = SuperConnect.objects.all()

for connection in connections:
  connection.connect()
  connection.dostuff

I've looked around and found some hacks but they look questionable and may require me to go to the database for each item in order to retrieve data I probably already have... 我环顾四周,发现了一些黑客,但他们看起来有问题,可能要求我去每个项目的数据库,以便检索我可能已经拥有的数据...

Somebody please rescue me :) or I am going to go with this hack: 有人请救我:)或者我会去讨论这个黑客:

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)

As you mentioned in your question, the problem with your solution is that it generates a SQL query for every object instead of using one SQL in = (id1, id2) query. 正如您在问题中提到的,您的解决方案的问题是它为每个对象生成SQL查询,而不是in = (id1, id2)查询中使用一个SQL。 Proxy models cannot contain additional database fields, so there is no need for extra SQL queries. 代理模型不能包含其他数据库字段,因此不需要额外的SQL查询。

Instead, you can convert a SuperConnect object to the appropriate type in SuperConnect.__init__ , using the __class__ attribute: 相反,您可以使用__class__属性将SuperConnect对象转换为SuperConnect SuperConnect.__init__的相应类型:

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

There is no need for custom managers or querysets, the correct type is set when the SuperConnect object is initialized. 不需要自定义管理器或查询集,在初始化SuperConnect对象时设置正确的类型。

How about putting all the logic in one class. 如何将所有逻辑放在一个类中。 Something like this: 像这样的东西:

def connect(self):
    return getattr(self, "connect_%s" % self.type)()

def connect_aol(self):
    pass # AOL stuff

def connect_yahoo(self):
    pass # Yahoo! stuff

In the end you have your type field and you should be able to do most (if not all) things that you can do with seperate proxy classes. 最后你有了你的type字段,你应该能够做大部分(如果不是全部)你可以用单独的代理类做的事情。

If this approach doesn't solve your specific use cases, please clarify. 如果这种方法无法解决您的具体用例,请澄清。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM