我正在为我的所有模型添加一个slug用于序列化,所以我定义了一个使用django_autoslug中的AutoSlugField的抽象基类。
class SluggerModel(models.Model):
slug = AutoSlugField(unique=True, db_index=False)
class Meta:
abstract=True
我还定义了一个自定义管理器和一个natural_key方法,此时我有大约20个子类,因此除了定义字段的单行之外,还有一些使得使用抽象基本模型的东西值得。
但是,我希望能够切换一些默认参数来初始化某些子模型的AutoSlugField
,同时仍然可以使用抽象基类。例如,我希望其中一些人使用populate_from
选项,指定其特定模型中的字段,而其他人则使用db_index=True
而不是默认值(False
)。
我开始尝试使用自定义Metaclass,使用在每个子模型的内部Meta类中定义的自定义选项,但这成为了老鼠的巢。我可以接受有关该方法或任何其他建议的指导。
答案 0 :(得分:13)
一种解决方案是动态构建抽象基类。例如:
def get_slugger_model(**slug_kwargs):
defaults = {
'unique': True,
'db_index': False
}
defaults.update(slug_kwargs)
class MySluggerModel(models.Model):
slug = AutoSlugField(**defaults)
class Meta:
abstract = True
return MySluggerModel
class MyModel(get_slugger_model()):
pass
class MyModel2(get_slugger_model(populate_from='name')):
name = models.CharField(max_length=20)
答案 1 :(得分:0)
更新:我开始使用以下解决方案,这很丑陋,并切换到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所以你能做什么,所以也许这就是答案。