1

In django (v1.9) is there a way to set a field that is defined in the base class to use a different default value in the different descendant classes?

class Base(models.Model):
    OBJ_TYPES = (
        ('type_a', 'Type A'),
        ('type_b', 'Type B'),
        ('type_c', 'Type C'),
        ('type_d', 'Type D'),
    )
    obj_type = models.CharField(choices=OBJ_TYPES, default='type_a')

class GenericChild(Base):
    # obj_type defaults to type_a
    pass

class TypeDChild(Base)
    # Want obj_type to default to type_d
    # This causes error (local field clashes...)
    obj_type = models.CharField(choices=OBJ_TYPES, default='type_d')
Alexander
  • 105,104
  • 32
  • 201
  • 196
Jamie Czuy
  • 1,343
  • 1
  • 11
  • 16
  • default can be a callable, you can call a function checking the related model subtype and returning the appropriate value. – simone cittadini Jul 28 '16 at 15:58
  • @simonecittadini the default can be a callable, but you don't have access to `self`, so you can't check the subtype inside the callable. – Alasdair Jul 28 '16 at 15:59
  • It seems that you can't do that. See this question http://stackoverflow.com/questions/2344751/in-django-model-inheritance-does-it-allow-you-to-override-a-parent-models-a – JustLive Jul 28 '16 at 16:40
  • @JustLive - I was about to say "not exactly the same - I am not overwriting the field just the default" but then thinking about how it would be done in SQL the default is part of the column definition. Ok - guess I need to set / enforce it in the front end. – Jamie Czuy Jul 28 '16 at 17:42

1 Answers1

0

Yes, it can be overriden, but probably not in a way that you would expect. Your modified code that will work:

class Base(models.Model):
    OBJ_TYPES = (
        ('type_a', 'Type A'),
        ('type_b', 'Type B'),
        ('type_c', 'Type C'),
        ('type_d', 'Type D'),
    )
    obj_type = models.CharField(choices=OBJ_TYPES, default='type_a')

    # Make sure you do this, always always always set your base classes to abstract
    class Meta:
        abstract = True

class GenericChild(Base):
    # obj_type defaults to type_a
    pass

class TypeDChild(Base)
    # Want obj_type to default to type_d
    # This causes error (local field clashes...)
    # obj_type = models.CharField(choices=OBJ_TYPES, default='type_d')
    pass
TypeDChild._meta.get_field('obj_type').default = 'type_d'

As you can see, you have to update the default after the class definition. Keep in mind, this may or may not work with future versions of Django, as they update the way model introspection works every few releases.

Titus P
  • 959
  • 1
  • 7
  • 16