Same field, different choices in Django model subclasses
Is it possible to use different choices
for subclasses of models? The following code should give you an idea
class Clothing(models.Model):
size = models.CharField(max_length=1)
colour = models.CharField(max_length=1)
SHIRT_SIZES = {
'S','Small',
'M','Medium',
'L','Large',
}
class TShirt(mo开发者_运维技巧dels.Model):
size = models.CharField(max_length=1, choices=SHIRT_SIZES)
MENS_CHOICES = {
'K','Black',
'R','Red',
'B','Blue',
}
class MensColours(models.Model):
colour = models.CharField(max_length=1, choices=MENS_CHOICES)
class MensShirt(MensColours, TShirt):
class Meta:
verbose_name = "men's shirt"
WOMENS_CHOICES = {
'P','Pink',
'W','White',
'B','Brown',
}
class WomensColours(models.Model):
colour = models.CharField(max_length=1, choices=WOMENS_CHOICES)
class WomensShirt(WomensColours, TShirt):
class Meta:
verbose_name = "women's shirt"
The reason I'm using mixins is that I have attributes/choices that can be shared between different models (e.g. also having women's/men's pants, which may have the same colour choices but different size choices than the TShirts). Overall, however, all clothing has a colour and a size.
How should I do this?
No. Potential field choices are fixed in the parent. You can get around this in a form by specifying the valid choices for the form field, but you cannot change the fundamental nature of the model field.
Mixins are the right way to solve that kind of issues. But if you have to make fields depend on each other in every single class, there is another way.
You have to define your field in the definition of the class. That means you have to hack the class building process. Because after it had been created it becomes concrete. I really have no idea if there is any chance to change the field after that.
from django.db import models
from django.db.models.base import ModelBase
class ApparelMeta(ModelBase):
def __new__(mcs, name, bases, attrs):
meta = attrs.get('Meta', None)
# We should check if it is the end class
# because django's class inheritance is not pythonic
if meta and not getattr(meta, 'abstract', None) \
and not attrs.get('_deferred'):
sizes = models.CharField(max_length=1, choices=attrs['SIZES'])
colors = models.CharField(max_length=1, choices=attrs['COLORS'])
return super(ApparelMeta, mcs).__init__(mcs, name, bases, attrs)
class Apparel(models.Model):
__metaclass__ = ApparelMeta
class Meta:
abstract = True
index_together = (
('sizes', 'colors'),
)
# Now you can create all that classes: men, women, children
class MensApparel(Apparel):
COLORS = {
'K','Black',
'R','Red',
'B','Blue',
}
SIZES = {
'S','Small',
'M','Medium',
'L','Large',
}
class WomensApparel(Apparel):
COLORS = {
'R','Red',
}
SIZES = {
'S','Small',
}
精彩评论