2016-08-24 113 views
0

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。在当前实现PRIVACY_CHOICESUserProfile不覆盖PRIVACY_CHOICESAbstractProfile。如何解决?在未来可能是其他机型,其中也应该有自己的PRIVACY_CHOICES

我使用Django 1.10

+0

不是在抽象中定义隐私字段,而是为什么不把它移动到CompanyProfile而不是在抽象中定义它? –

+0

你的意思是根据需要在许多课程中重复相同的字段?不是干的方式:) – TitanFighter

+0

我看到两个模型和两个定义。看起来不像我。而且,DRY是重要的,但通常运营解决方案更重要。我想这是最好的另一个场地的讨论。 –

回答

0

找到解决方案。

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

未修改的形式从抽象类需要选择。现在不需要在不同的类中重复相同的字段。如果所有类都有自己的选择版本,那么方法可以通过适当的修改(至少改变类名)复制到这些类,甚至可以作为一个单独的函数,但这是另一回事。