更新:我从以下解决方案开始,这很丑陋,然后切换到 Daniel 的解决方案,但事实并非如此。我把我的留在这里以供参考。
这是我的 Metaclass 捕鼠器,它似乎正在工作(尚未进行广泛的测试)。
class SluggerMetaclass(ModelBase):
"""
Metaclass hack that provides for being able to define 'slug_from' and
'slug_db_index' in the Meta inner class of children of SluggerModel in order to set
those properties on the AutoSlugField
"""
def __new__(cls, name, bases, attrs):
# We don't want to add this to the SluggerModel class itself, only its children
if name != 'SluggerModel' and SluggerModel in bases:
_Meta = attrs.get('Meta', None)
if _Meta and hasattr(_Meta, 'slug_from') or hasattr(_Meta, 'slug_db_index'):
attrs['slug'] = AutoSlugField(
populate_from=getattr(_Meta, 'slug_from', None),
db_index=getattr(_Meta, 'slug_db_index', False),
unique=True
)
try:
# ModelBase will reject unknown stuff in Meta, so clear it out before calling super
delattr(_Meta, 'slug_from')
except AttributeError:
pass
try:
delattr(_Meta, 'slug_db_index')
except AttributeError:
pass
else:
attrs['slug'] = AutoSlugField(unique=True, db_index = False) # default
return super(SlugSerializableMetaclass, cls).__new__(cls, name, bases, attrs)
现在SlugModel
看起来基本上是这样的:
class SluggerModel(models.Model):
__metaclass__ = SluggerMetaclass
objects = SluggerManager()
# I don't define the AutoSlugField here because the metaclass will add it to the child class.
class Meta:
abstract = True
我可以通过以下方式达到预期的效果:
class SomeModel(SluggerModel, BaseModel):
name = CharField(...)
class Meta:
slug_from = 'name'
slug_db_index = True
对于具有多个抽象父模型的模型,我必须将 SluggerModel 放在继承列表的第一位,否则其他父模型不会拾取字段并且验证失败;但是,我无法解释原因。
我想我可以把它作为我自己问题的答案,因为它有效,但我希望有更好的方法,因为它有点丑陋。再说一遍,hax 就是 hax,所以你能做什么,所以也许这就是答案。