Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django : Change default value for an extended model class

I posted a similar question a while earlier, but this one is different. I have a model structure of related classes like:

class Question(models.Model):
     ques_type = models.SmallIntegerField(default=TYPE1, Choices= CHOICE_TYPES)

class MathQuestion(Question):
     //Need to change default value of ques_type here 
     // Ex: ques_type = models.SmallIntegerField(default=TYPE2, Choices= CHOICE_TYPES)

I want to change the default value of ques_type in the derived class. How should i accomplish this?

like image 633
Neo Avatar asked Feb 05 '11 00:02

Neo


3 Answers

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(...).

like image 119
validname Avatar answered Nov 07 '22 07:11

validname


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
like image 15
Reiner Gerecke Avatar answered Nov 07 '22 06:11

Reiner Gerecke


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.
like image 2
user680453 Avatar answered Nov 07 '22 07:11

user680453