在模型上覆盖__getattr__会破坏django-model-utils InheritanceManager

时间:2019-09-08 00:37:18

标签: python django

我正在使用django-model-utils程序包,并且试图覆盖在我也为其定义InheritanceManager的模型上的 getattr

我有多个继承自同一模型的模型,并且我在父模型上调用.select_subclasses()以获得子模型的查询集。

问题是InheritanceManager在ObjectDoesNotExist异常上进行了try / except,而我的 getattr 引发了AttributeError异常(这是标准的)。这会导致查询集失败,因为InheritanceManager无法捕获AttributeError。

有关如何解决此问题的任何想法。我不认为我想在我的 getattr 方法中引发ObjectDoesNotExist ..但不确定要尝试什么。

谢谢!

models.py:

from django.db import models
from model_utils.managers import InheritanceManager


class Item(models.Model):
    name = models.CharField(max_length=32)
    description = models.CharField(max_length=100, default='')

    objects = InheritanceManager()

    def __getattr__(self, name):
        raise AttributeError('Attribute {} not found on item {}'.format(name, self.name))


class ItemA(Item):
    attribute_a = models.CharField(max_length=10)


class ItemB(Item):
    attribute_b = models.CharField(max_length=10)

测试:

if __name__ == "__main__":
    # Initialize Django Environment
    import os, sys
    sys.path.append('C:/Data/Code/quicktest/testproject')
    os.environ['DJANGO_SETTINGS_MODULE'] = 'testproject.settings'
    import django
    django.setup()

from testapp.models import Item

for item in Item.objects.all().select_subclasses():
    print(item.name)

结果:

Traceback (most recent call last):
  File "C:/Data/Code/quicktest/testproject/testapp/tests.py", line 11, in <module>
    for item in Item.objects.all().select_subclasses():
  File "C:\Data\Code\quicktest\venv\lib\site-packages\django\db\models\query.py", line 274, in __iter__
    self._fetch_all()
  File "C:\Data\Code\quicktest\venv\lib\site-packages\django\db\models\query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Data\Code\quicktest\venv\lib\site-packages\model_utils\managers.py", line 28, in __iter__
    sub_obj = queryset._get_sub_obj_recurse(obj, s)
  File "C:\Data\Code\quicktest\venv\lib\site-packages\model_utils\managers.py", line 211, in _get_sub_obj_recurse
    node = getattr(obj, rel)
  File "C:\Data\Code\quicktest\testproject\testapp\models.py", line 12, in __getattr__
    raise AttributeError('Attribute {} not found on item {}'.format(name, self.name))
AttributeError: Attribute itema not found on item some itemb

1 个答案:

答案 0 :(得分:0)

我找到了可行的解决方案。虽然不确定我对此感到兴奋。

def __getattr__(self, name):

    # Do magical stuff that getattr is intended for


    # Catch if the reason this was called was because its a reverse one to one that doesn't exist
    try:
        model_field = self.__class__._meta.get_field(name)
        if isinstance(model_field, models.fields.reverse_related.OneToOneRel):
            return None
    except models.fields.FieldDoesNotExist:
        pass

    raise AttributeError('Attribute {} not found on item {}'.format(name, self.name))

我觉得InheritanceManager应该接受AttributeError异常,但这是可行的