在 Django 项目中,我有一个扩展 Django 用户模型的模块,类似于以下内容:
from django.contrib.auth.models import User
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
User.add_to_class('__str__', __str__)
我注意到这行得通。但是,如果我尝试定义一个 __getattr__ 方法,如下所示:
def __getattr__(self, attr):
if self.user_profile:
return getattr(self.user_profile, attr)
else:
raise AttributeError(f"'{self.__class__.__name__}' has no attribute '{attr}'")
导入模块时出现以下错误:
(lucy-web-CVxkrCFK) bash-3.2$ python manage.py shell
Traceback (most recent call last):
File "manage.py", line 28, in <module>
execute_from_command_line(sys.argv)
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
utility.execute()
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/django/core/management/__init__.py", line 347, in execute
django.setup()
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/django/__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/django/apps/registry.py", line 112, in populate
app_config.import_models()
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/site-packages/django/apps/config.py", line 198, in import_models
self.models_module = import_module(models_module_name)
File "/Users/kurtpeek/.local/share/virtualenvs/lucy-web-CVxkrCFK/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/lucy_web/models/__init__.py", line 25, in <module>
from .user import User
File "<frozen importlib._bootstrap>", line 1019, in _handle_fromlist
TypeError: __getattr__() missing 1 required positional argument: 'attr'
难道不能用这种方式用__getattr__方法扩展User模型吗?
请您参考如下方法:
在 python 3.7 中,如果您定义一个名为 __getattr__ 的模块级函数 it will be a module level attribute getter function ,类似于类 getattr。看来你是无意的。模块级 __getattr__ 具有与类方法不同的调用签名。
Specification
The
__getattr__function at the module level should accept one argument which is the name of an attribute and return the computed value or raise an AttributeError:def __getattr__(name: str) -> Any: ...
尝试将函数重命名为其他名称,以避免无意中隐藏保留的函数名称。
def user_getattr(self, attr):
...
User.add_to_class('__getattr__', user_getattr)
This PEP may break code that uses module level (global) names
__getattr__and__dir__. (But the language reference explicitly reserves all undocumented dunder names, and allows "breakage without warning")
And here's what the language reference says:
Any use of
__*__names, in any context, that does not follow explicitly documented use, is subject to breakage without warning.
因此,您还应该重命名您的自定义 __str__ 函数,以避免将来可能出现的损坏。
