>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 [email protected].
To post to this group, send email to [email protected].
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.