如何在Django/Python中断言类拥有类专属属性(区分模型字段与类属性)?
解决Django模型子类classproperty与父类字段的测试区分问题
这个问题的核心在于Django模型的数据库字段在类层面本身就是类属性,hasattr()会沿着继承链查找属性,所以它无法区分子类自己定义的classproperty和从父类继承来的数据库字段。要实现你的测试需求,我们可以从直接检查类的属性定义和验证属性类型两个角度入手。
方案一:检查子类的__dict__字典
类自己定义的属性(包括通过classproperty装饰的属性)会直接存在于类的__dict__中,而继承来的属性不会。结合类型检查,就能准确判断子类是否定义了目标classproperty:
from django.test import TestCase from django.utils.decorators import classproperty from .models import Parent, Child class ModelPropertyTests(TestCase): def test_child_has_own_somefield_classproperty(self): # 确认子类自己定义了somefield属性 self.assertIn('somefield', Child.__dict__) # 验证该属性是classproperty类型 self.assertIsInstance(Child.__dict__['somefield'], classproperty) def test_parent_somefield_is_model_field(self): # 父类的somefield是数据库字段,不是classproperty self.assertIn('somefield', Parent.__dict__) self.assertNotIsInstance(Parent.__dict__['somefield'], classproperty)
方案二:使用inspect.getattr_static验证属性来源
inspect.getattr_static可以获取类属性的原始值(不触发描述符的__get__方法),通过对比子类和父类的属性对象,能明确区分是继承来的还是自己定义的:
from django.test import TestCase from django.db import models from django.utils.decorators import classproperty from inspect import getattr_static from .models import Parent, Child class ModelPropertyTests(TestCase): def test_child_somefield_is_custom_classproperty(self): child_attr = getattr_static(Child, 'somefield') parent_attr = getattr_static(Parent, 'somefield') # 子类的属性对象和父类的不是同一个(说明是自己定义的) self.assertIsNot(child_attr, parent_attr) # 验证子类的属性是classproperty self.assertIsInstance(child_attr, classproperty) # 验证父类的属性是Django模型字段 self.assertIsInstance(parent_attr, models.TextField)
为什么hasattr()无法满足需求?
Django在加载模型类时,会把数据库字段注册为类属性,所以Parent.somefield本身就是一个TextField实例,hasattr(Parent, 'somefield')会返回True——这和你原本的测试预期不符。而子类Child继承了这个属性后,又用classproperty覆盖了它,hasattr(Child, 'somefield')自然也返回True,所以无法通过hasattr()区分二者的差异。
内容的提问来源于stack exchange,提问作者everspader
相关产品推荐
相关产品推荐

