Python: сохранение типа класса в переменной класса при инициализации класса дурига - PullRequest
1 голос
/ 23 февраля 2020

Я пытаюсь инициализировать поле объектов с классом, который должен знать тип, который его использует:

class Device(Model):
    objects = AbstractManager(Device)

    # the rest of the class here

Вот как определяется AbstractManager:

class AbstractManager:
    def __init__(self, cls: type):
        self.cls = cls

    def all(self):
        result = []

        for cls in self._get_subclasses():
            result.extend(list(cls.objects.all()))

        return result

    def _get_subclasses(self):
        return self.cls.__subclasses__()

Позже я могу вызвать это и вернуть all () из всех подклассов:

Device.objects.all()

Проблема здесь в том, что я не могу использовать Device при инициализации объектов Device.objects, поскольку Device все еще не инициализирован.

В качестве обходного пути я инициализирую это вне класса, но должен быть лучший способ:

class Device(Model):
    objects = None

    # the rest of the class here

Device.objects = AbstractManager(Device)

PD: У меня есть фон C # / C ++, так что, возможно, я слишком много думая об этом в типизированном мышлении, не могу сказать

Ответы [ 2 ]

2 голосов
/ 23 февраля 2020

Ты не обязан это делать. Django автоматически вызовет метод contribute_to_class, где он передаст модель, а для менеджера он будет сохранен в self.model. Таким образом, вы можете просто реализовать это как:

from django.db.models.manager import ManagerDescriptor

class AbstractManager(models.Manager):

    def all(self):
        result = []

        for cls in self._get_subclasses():
            result.extend(list(cls.objects.all()))

        return result

    def contribute_to_class(self, model, name):
        self.name = self.name or name
        self.model = model
        setattr(model, name, <b>AbstractManagerDescriptor(</b>self<b>)</b>)

        model._meta.add_manager(self)

    def _get_subclasses(self):
        return <b>self.model</b>.__subclasses__()

class <b>AbstractManagerDescriptor</b>(ManagerDescriptor):

    def __get__(self, instance, cls=None):
        if instance is not None:
            raise AttributeError("Manager isn't accessible via %s instances" % cls.__name__)

        if cls._meta.swapped:
            raise AttributeError(
                "Manager isn't available; '%s.%s' has been swapped for '%s'" % (
                    cls._meta.app_label,
                    cls._meta.object_name,
                    cls._meta.swapped,
                )
            )

        return cls._meta.managers_map[self.manager.name]

и добавить менеджера как:

class Device(models.Model):
    objects = <b>AbstractManager()</b>

При этом я не уверен, что это хорошая идея по двум причинам :

  1. вы возвращаете список, и обычно .all() возвращает QuerySet, таким образом, вы здесь «уничтожаете» лень набора запросов, что может привести к дорогостоящим запросам; и
  2. если использовать, например, Device.objects.filter(), он просто обойдется.

Возможно, вы захотите создать подкласс подкласса запросов, а затем попытаться реализовать его по-другому.

2 голосов
/ 23 февраля 2020

Вам не нужно добавлять дополнительные логи c для этого. Django позволяет получить доступ к классу модели из менеджера, используя атрибут self.model:

def _get_subclasses(self):
    return self.model.__subclasses__()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...