2012-12-09 6 views

risposta

13

L'impostazione predefinita della colonna si applica solo alle istruzioni INSERT e UPDATE e pertanto non viene applicata fino alla sessione .flush().

Per visualizzare lo stesso valore sulle nuove istanze prima di svuotare, è necessario applicare l'impostazione predefinita quando viene creata una nuova istanza; nel metodo __init__ dell'oggetto User:

class User(Base): 
    __tablename__ = 'users' 

    def __init__(self, **kwargs): 
     if 'money' not in kwargs: 
      kwargs['money'] = self.__table__.c.money.default.arg 
     super(User, self).__init__(**kwargs) 

    id = Column(Integer, primary_key=True) 
    money = Column(Integer, default=100) 

Se non money attributo è stato impostato, si aggiunge uno direttamente basato sul predefinito configurato per la colonna.

Si noti che i valori predefiniti sono espressioni SQL, non i valori Python, quindi potrebbe essere necessario mapparli prima agli oggetti Python. Ad esempio, un campo booleano avrà un valore di stringa predefinito 'false' o 'true', non un oggetto booleano Python di False o True Python.

+2

Quindi, se voglio riempire tutti i valori predefiniti di un oggetto più complesso, devo eseguire un'iterazione su tutte le colonne, vedere se ha un valore predefinito e riempilo nel rispettivo attributo. Ok, posso farlo. Mi chiedo solo: questa funzionalità deve esistere in sqlalchemy, perché ne ha bisogno al tempo di inserimento/aggiornamento comunque. E mi chiedo, perché non è esposto agli utenti. – Elrond

+0

@Errond: probabilmente perché i valori predefiniti sono diretti al lato SQL; puoi avere valori predefiniti non statici espressi anche come SQL. –

+2

Mi piace la soluzione di Martijn, sembra molto completa. L'ho sempre fatto in passato, il che potrebbe essere un po 'meno codice in quanto non è necessario scorrere le colonne. http://stackoverflow.com/questions/13384996/how-do-i-set-attribute-default-values-in-sqlalchemy-declarative/13390300#13390300 –

7

Ho scoperto un meccanismo per inserire automaticamente alcune impostazioni predefinite quando viene creata un'istanza. Sto migrando da un ORM interno che imposta i valori predefiniti durante la creazione dell'istanza, quindi ho dovuto conservare questo comportamento e non volevo toccare ogni definizione del modello.

BaseModel = declarative_base() 

class Base(BaseModel): 
    __abstract__ = True 

    def __init__(self, **kwargs): 
     for attr in self.__mapper__.column_attrs: 
      if attr.key in kwargs: 
       continue 

      # TODO: Support more than one value in columns? 
      assert len(attr.columns) == 1 
      col = attr.columns[0] 

      if col.default and not callable(col.default.arg): 
       kwargs[attr.key] = col.default.arg 

     super(Base, self).__init__(**kwargs) 

La principale limitazione è che sono supportate solo le impostazioni predefinite non richiamabili. Le impostazioni predefinite callable e quelle che utilizzano una query del database richiedono un contesto di esecuzione che non è disponibile al momento della creazione dell'istanza. Inoltre, non ho scoperto un caso dove len(ColumnProperty.columns) != 1 ma non è supportato neanche.

1

Da quando ho bisogno dei valori di default non necessariamente nel costruttore, ma a volte da altri luoghi, mi si avvicinò con una funzione, che ho aggiunto alla mia classe di base Oggetto:

Base = declarative_base() 
class ItemBase(Base): 
    __abstract__ = True 
    def _ensure_defaults(self): 
     for column in self.__table__.c: 
      if getattr(self, column.name) is None and column.default is not None and column.default.is_scalar: 
       setattr(self, column.name, column.default.arg) 

che ovviamente non funziona per callable. Non riuscivo a capire come chiamarlo, e forse è per il meglio (senti come hackerare il pensiero già).

Con questa posso fare qualcosa di simile:

class User(ItemBase): 
    # ... inheritance, columns and stuff 
    def __init__(self): 
     self._ensure_defaults() 

Posso anche chiamare il metodo non in __init__, ma anche da altri metodi, in caso Ho solo bisogno di fare affidamento sui valori in circostanze particolari (che Ho finito per rimuovere più tardi, poiché era troppo confuso). Ancora in alcuni casi questo potrebbe essere più flessibile della soluzione di @JamesEmerton.

Problemi correlati