>From the doc: "Abstract base classes are useful when you want to put some 
common information into a number of other models". In my current project I 
put all common fields in abstact class, but those fields that use 'choice' 
option may have different choices in different child classes.

Code Example:

class AbstractProfile(models.Model):
    # Basic choices, which may vary in different classes
    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)
    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')),
    )

    GENDER_CHOICES = (
        (1, _('man')),
        (2, _('woman')),
    )

    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)

    gender = models.IntegerField(_('gender'), null=True, blank=True, choices
=GENDER_CHOICES)

    avatar = models.ImageField(upload_to='users/avatar', null=True, blank=
True)

class CompanyProfile(AbstractProfile):
    PRIVACY_CHOICES = (*** new choices, which are different to those which 
are in abstract class ***)

class TeamProfile(AbstractProfile):
    pass

There is a proposition to add to the 'class Meta' a new attribute, which 
lets to define, whether to use CHOICES from abstract class or use those 
which exists in the current class, something like:
class UserProfile(AbstractProfile):
    PRIVACY_CHOICES = (
        (1, _('all')),
        (2, _('friends')),
        (3, _('friends of friends')),
        (4, _('only me')),
    )

    GENDER_CHOICES = (
        (1, _('man')),
        (2, _('woman')),
    )

    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)

    gender = models.IntegerField(_('gender'), null=True, blank=True, choices
=GENDER_CHOICES)

    avatar = models.ImageField(upload_to='users/avatar', null=True, blank=
True)

    class Meta:
        use_choices = [PRIVACY_CHOICES]

Possible variants:
Variant A: Use CHOICES from abstract class - do not add anything to 'class 
Meta'
Variant B: Use CHOICES from current class instead of abstract class - add:
class Meta: 
    use_choices = [*** list of choices of current class **]

Variant C: Same as B, but change format a bit:
class Meta: 
    use_choices = ((ABSTRACT_CHOICES_NAME1, CURRENT_CLASS_CHOICES_NAME1), (
ABSTRACT_CHOICES_NAME2, CURRENT_CLASS_CHOICES_NAME2),)
just in case, if a developer for some reasons have different names of 
choices

This feature lets to have development process as DRY as possible, which is 
the reason why abstract class exists.

In order to solve it, currenty I use the next code:
# models.py
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
    *** rest fields ***

# forms.py
class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile()  # old_version was: model = UserProfile
        fields = (*** fields ***)
but I dont like this way.

Thanks

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/bc4b5ecb-0276-413f-b18f-1d26cd7bf6b4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to