如何覆盖抽象 class 的选择?
How can I override choices of abstract class?
我有 AbstractProfile
预定义模型 PRIVACY_CHOICES
:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
UserProfile
应该有来自 AbstractProfile
的字段,但有自己的 PRIVACY_CHOICES
。在当前实现中,UserProfile
的 PRIVACY_CHOICES
不会覆盖 AbstractProfile
的 PRIVACY_CHOICES
。怎么可能解决?以后可能会有其他型号,应该也有自己的PRIVACY_CHOICES
我使用 Django 1.10
找到解决方案。
models.py:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
# NEW PIECE OF CODE
def __init__(self, *args, **kwargs):
def get_class_attrs(cls):
return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
super(UserProfile, self).__init__(*args, **kwargs)
all_fields = get_class_attrs(UserProfile)
for each_field in all_fields:
# all fields with '_privacy' in the name have 'choice' option
if '_privacy' in each_field:
self._meta.get_field(each_field).choices = self.PRIVACY_CHOICES
default_privacy_choice = self.PRIVACY_CHOICES[0][0]
if self._meta.get_field(each_field).default != default_privacy_choice:
self._meta.get_field(each_field).default = default_privacy_choice
# END OF NEW PIECE OF CODE
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
class CompanyProfile(AbstractProfile):
pass
class OneMoreClass(AbstractProfile):
pass
还有必要修改forms.py:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile() # old_version was: model = UserProfile
fields = ('title',
'first_name', 'last_name', 'names_privacy',
'birth_date', 'birth_date_privacy',
'info', 'info_privacy',
'city', 'city_privacy', 'address', 'address_privacy',
'avatar',)
未修改的形式采用摘要 class 中的选项。现在不需要在不同的 class 中重复相同的字段。如果所有 classes 都有自己的选择版本,那么可以将方法 def __init__
复制到那些 classes 并进行适当的修改(至少要更改 class 名称),甚至可以作为一个单独的功能,但这是另一回事了。
我有 AbstractProfile
预定义模型 PRIVACY_CHOICES
:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
UserProfile
应该有来自 AbstractProfile
的字段,但有自己的 PRIVACY_CHOICES
。在当前实现中,UserProfile
的 PRIVACY_CHOICES
不会覆盖 AbstractProfile
的 PRIVACY_CHOICES
。怎么可能解决?以后可能会有其他型号,应该也有自己的PRIVACY_CHOICES
我使用 Django 1.10
找到解决方案。
models.py:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
# NEW PIECE OF CODE
def __init__(self, *args, **kwargs):
def get_class_attrs(cls):
return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
super(UserProfile, self).__init__(*args, **kwargs)
all_fields = get_class_attrs(UserProfile)
for each_field in all_fields:
# all fields with '_privacy' in the name have 'choice' option
if '_privacy' in each_field:
self._meta.get_field(each_field).choices = self.PRIVACY_CHOICES
default_privacy_choice = self.PRIVACY_CHOICES[0][0]
if self._meta.get_field(each_field).default != default_privacy_choice:
self._meta.get_field(each_field).default = default_privacy_choice
# END OF NEW PIECE OF CODE
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
class CompanyProfile(AbstractProfile):
pass
class OneMoreClass(AbstractProfile):
pass
还有必要修改forms.py:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile() # old_version was: model = UserProfile
fields = ('title',
'first_name', 'last_name', 'names_privacy',
'birth_date', 'birth_date_privacy',
'info', 'info_privacy',
'city', 'city_privacy', 'address', 'address_privacy',
'avatar',)
未修改的形式采用摘要 class 中的选项。现在不需要在不同的 class 中重复相同的字段。如果所有 classes 都有自己的选择版本,那么可以将方法 def __init__
复制到那些 classes 并进行适当的修改(至少要更改 class 名称),甚至可以作为一个单独的功能,但这是另一回事了。