Django Group.objects 猴子补丁问题 - 'NoneType' 对象没有属性 '_meta'

Django Group.objects monkey patch problem - 'NoneType' object has no attribute '_meta'

我是初级开发人员,我正在尝试猴子补丁 django.contrib.auth.models 组经理。 (Python 2.7.15,Django 1.8)

有我的代码:

class DefaultGroupManager(models.Manager):
    def get_queryset(self):
        tests = Test.objects.values()
        tests_ids = [test['virtual_group_id'] for test in tests]
        return super(DefaultGroupManager, self).get_queryset().exclude(id__in=tests_ids)


Group.objects = DefaultGroupManager()

然后我打开pythonshell测试一下:

python manage.py shell

from django.contrib.auth.models import Group

t = Group.objects.all()

在执行此命令后我收到错误消息:

  File "<console>", line 1, in <module>
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/manager.py", line 228, in all
    return self.get_queryset()
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/registration/models.py", line 13, in get_queryset
    return super(DefaultGroupManager, self).get_queryset().exclude(id__in=tests_ids)
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 686, in exclude
    return self._filter_or_exclude(True, *args, **kwargs)
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 695, in _filter_or_exclude
    clone.query.add_q(~Q(*args, **kwargs))
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1310, in add_q
    clause, require_inner = self._add_q(where_part, self.used_aliases)
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1338, in _add_q
    allow_joins=allow_joins, split_subq=split_subq,
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1150, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg)
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1036, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
  File "/home/adrian/Dokumenty/Pycharm Projects/backend/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 246, in get_meta
    return self.model._meta
AttributeError: 'NoneType' object has no attribute '_meta'

我不知道怎么了:(

如有任何帮助,我将不胜感激!

经理需要设置 model 属性。这通常由 Model 的元类在导入时完成,但由于您绕过了它,因此您必须自己设置它:

class DefaultGroupManager(models.Manager):
    model = Group

    def get_queryset(self):
        # this avoids a useless db query + python loop
        tests_ids = Test.objects.values_list('virtual_group_id', flat=True)
        return super(DefaultGroupManager, self).get_queryset().exclude(id__in=tests_ids)

编辑:愚蠢的我,正确初始化管理器还需要其他步骤,部分Manager.contribute_to_class中实现,部分没有(抱歉,没有是时候进一步调查了,但你可以阅读 Django 源代码来找出答案)... IOW 使它(有点)"work" 你需要:

# You also want to inherit from GroupManager, some code
# relies on extra stuff defined here

from django.contrib.auth.models import GroupManager

class DefaultGroupManager(GroupManager):    
    def get_queryset(self):
        tests_ids = Test.objects.values_list('virtual_group_id', flat=True)
        return super(DefaultGroupManager, self).get_queryset().exclude(id__in=tests_ids)


manager = DefaultManager()
manager.contribute_to_class(Group, "objects")
Group._meta.managers_map["objects"] = manager

但是:这充其量是脆弱的(实际上我什至不能保证它在 Django > 1.10.x 上工作),并且 might not work as you expect for all situations .

你不应该那样的猴子补丁:Django 在 class 的构造中有一些逻辑,它将 "inject" 中的额外数据领域、经理等

通过简单的猴子修补,您可以省略这些步骤。然而,经理有一个 contribute_to_class 方法,所以你可以像猴子一样修补它:

dgm = DefaultGroupManager()
dgm.contribute_to_class(Group, 'objects')
Group.objects = dgm

也就是说,在我看来,如果您覆盖 .objects 管理器,通常会导致很多麻烦,因为很多 Django 代码会假设使用 Group.objects,您会得到 所有 个对象。此外,许多 Django 工具仍然有可能获取 all Groups,因为这些可能与 Model._base_manager [Django-doc].

一起使用

所以虽然它(可能)没有违反任何合同,但它可能会导致比其价值更多的麻烦。

如果您 运行 进行测试,通常您会在 孤立的 环境中进行测试。此外集成测试,通常也在单独的数据库上 运行。