如何覆盖抽象类的选择?

时间:2016-08-24 17:23:04

标签: django python-3.x choicefield

我拥有预定义AbstractProfile的{​​{1}}模型:

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的当前实现中,PRIVACY_CHOICES不会覆盖UserProfile的{​​{1}}。怎么可能解决?将来可能是其他模型,也应该有自己的PRIVACY_CHOICES

我使用Django 1.10

1 个答案:

答案 0 :(得分:1)

找到解决方案。

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',)

未修改的表单从Abstract类中选择。现在不需要在不同的类中重复相同的字段。如果所有类都有自己的选择版本,那么可以将方法def __init__复制到那些具有适当修改的类(至少改变类名),或者甚至可以作为单独的函数,但这是另一个故事。