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(Que开发者_JAVA技巧stion):
//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?
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
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(...)
.
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.
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/
精彩评论