[Fixed]-Django : Change default value for an extended model class

15👍

First, in this use of inheritance it is (at least according to my tests) not possible to change the default of the field in the child class. MathQuestion and Question share the same field here, changing the default in the child class affects the field in the parent class.

Now if what only differs between MathQuestion and Question is the behaviour (so, MathQuestion doesn’t add any fields besides those defined in Question), then you could make it a proxy model. That way, no database table is created for MathQuestion.

from django.db import models

class Question(models.Model):
     ques_type = models.SmallIntegerField(default=2)

class MathQuestion(Question):

    def __init__(self, *args, **kwargs):
        self._meta.get_field('ques_type').default = 3
        super(MathQuestion, self).__init__(*args, **kwargs)

    class Meta:
        proxy = True

Test:

In [1]: from bar.models import *

In [2]: a=Question.objects.create()

In [3]: a.ques_type
Out[3]: 2

In [4]: b=MathQuestion.objects.create()

In [5]: b.ques_type
Out[5]: 3

5👍

Examples above are for proxy models. If you need to change default for model inherited from non-abstract base model you can do following:

from django.db import models


class Base(models.Model):
    field_name = models.CharField(...)


class Child(Base):
    def __init__(self, *args, **kwargs):
        kwargs['field_name'] = kwargs.get('field_name') or 'default value'
        super().__init__(*args, **kwargs)

Which will set default if it wasn’t passed directly on Model(...) or Model.objects.create(...).

2👍

This is easy to do using a closure.

from django.db import models

# You start here, but the default of 2 is not what you really want.

class Question(models.Model):
     ques_type = models.SmallIntegerField(default=2)

class MathQuestion(Question):

    def __init__(self, *args, **kwargs):
        self._meta.get_field('ques_type').default = 3
        super(MathQuestion, self).__init__(*args, **kwargs)

    class Meta:
        proxy = True

The closure allows you to define it how you like it.

from django.db import models

def mkQuestion(cl_default=2):
    class i_Question(models.Model):
        ques_type = models.SmallIntegerField(default=cl_default)

    class i_MathQuestion(i_Question):

        def __init__(self, *args, **kwargs):
            super(MathQuestion, self).__init__(*args, **kwargs)
    return i_MATHQUESTION


MathQuestion = mkQuestion()
MathQuestionDef3 = mkQuestion(3)

# Now feel free to instantiate away.

2👍

Use a Form or ModelForm, on which you can override the field. For models, set the default value in it’s __init__ method like so:

class Question(models.Model):
     ques_type = models.SmallIntegerField(default=2)

class MathQuestion(Question):

    def __init__(self, *args, **kwargs):
        super(MathQuestion, self).__init__(*args, **kwargs)
        self.ques_type = 3

    class Meta:
        proxy = True

Note that this has to be done after calling the parent class init.

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/

Leave a comment