2011-10-25 66 views
14

比方說,我有一些Django的模型,是一個抽象基類:如何在Django模型子類中更改字段參數?

class Foo(models.Model): 
    value=models.IntegerField() 

    class Meta: 
     abstract = True 

,它有兩個派生類,在這裏我想對字段的默認值是每個子類不同。我不能簡單地覆蓋該字段

class Bar(Foo): 
    value=models.IntegerField(default=9) 

因爲Django不會讓您覆蓋子類中的字段。我見過有關嘗試更改可用選項的帖子,但在這種情況下,我主要關心更改默認值。有什麼建議?

回答

7

按照其他答案中的建議重新定義保存方法的問題是,只有保存模型對象後才能設置值。 不具有此問題的另一種選擇是重新定義在子類中__init__(酒吧類):

def __init__(self, *args, **kwargs): 
    if 'value' not in kwargs: 
     kwargs['value'] = 9 
    super(Bar, self).__init__(*args, **kwargs) 
2

我認爲你想要做的事情是不可能的,至少在Django沒有。你必須在Django中看到繼承作爲超類的ForeignKey(這幾乎就是這樣),並且你不能改變FK關係中屬性的默認值。

因此,您可以做的最好的事情是重新定義save()方法。這將是這樣的:

def save(self, *args, **kwargs): 
    if not self.value: 
     self.value = 9 
    super(Bar, self).save(*args, **kwargs) 

而且,在富(超一流):

value = models.IntegerField(blank=True) 

,以避免與數據庫NOT NULL問題。

+0

如果我簡單地定義爲在基類中的所有元素的默認值,可能我們再只覆蓋了保存方法所有的子類,還是將在基類中定義的默認值導致實例變量永遠不會爲空? (也就是說,如果我在父類中定義了默認值,那麼在保存或初始化對象時是否添加了默認值?) – Zxaos

+1

同樣,您必須將Django中的繼承看作超類的FK,所以如果超類具有缺省值的字段,則子類中的字段也將具有缺省值的字段,因爲該字段實際上不是來自子類,而是來自超類。 – juliomalegria

0

定義一個metaclass(和一個基類),提供所有的子類給出的一個領域類型,與可以在子類中設置的,但不必是默認值:

from django.db import models 
class DefaultTextFieldMetaclass(models.base.ModelBase): 
    DEFAULT_TEXT = 'this is the metaclass default' 

    def __new__(mcs, name, parents, _dict): 
     if not (('Meta' in _dict) and hasattr(_dict['Meta'], 'abstract') and _dict['Meta'].abstract): 
      # class is concrete 
      if 'DEFAULT_TEXT' in _dict: 
       default = _dict['DEFAULT_TEXT'] 
      else:  # Use inherited DEFAULT_TEXT if available 
       default_set = False 
       for cls in parents: 
        if hasattr(cls, 'DEFAULT_TEXT'): 
         default = cls.DEFAULT_TEXT 
         default_set = True 
       if not default_set: 
        default = mcs.DEFAULT_TEXT 
      _dict['modeltext'] = models.TextField(default=default) 
     return super(DefaultTextFieldMetaclass, mcs).__new__(mcs, name, parents, _dict) 


class BaseTextFieldClass(models.Model): 
    class Meta(object): 
     abstract = True 
    __metaclass__ = DefaultTextFieldMetaclass 
    DEFAULT_TEXT = 'superclass default' 


class TextA(BaseTextFieldClass): 
    DEFAULT_TEXT = 'A default for TextA' 

class TextB(BaseTextFieldClass): 
    DEFAULT_TEXT = 'The default for TextB' 
    number = models.IntegerField(default=43) 

class TextC(BaseTextFieldClass): 
    othertext = models.TextField(default='some other field') 

除非你有一大堆的子類和/或扎入BaseTextFieldClass多種方法/屬性和假設,這可能是矯枉過正的......但它應該做OP所要求的。

1

https://stackoverflow.com/a/6379556/15690

實際上,你可以做到這一點,如下所示:

class BaseMessage(models.Model): 
    is_public = models.BooleanField(default=False) 
    # some more fields... 

    class Meta: 
     abstract = True 

BaseMessage._meta.get_field('is_public').default = True 

class Message(BaseMessage): 
    # some fields... 
相關問題