прокси-модели гетерогенных наборов запросов django - PullRequest
3 голосов
/ 12 октября 2010

Я пытаюсь понять, как использовать прокси-классы в 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 голос
/ 12 января 2013

Как вы упомянули в своем вопросе, проблема вашего решения заключается в том, что он генерирует 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.

0 голосов
/ 12 октября 2010

Как насчет размещения всей логики в одном классе.Примерно так:

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, и вы сможете делать большинство (если не все) вещи, которые вы можете делать с отдельными прокси-классами.1006 * Если этот подход не решает ваши конкретные случаи использования, уточните.

...