2012-12-09 7 views

Odpowiedz

13

Domyślna kolumna dotyczy tylko instrukcji INSERT i UPDATE, a zatem nie jest stosowana, dopóki użytkownik nie wykona sesji.

Aby zobaczyć tę samą wartość w nowych instancjach przed opróżnieniem, należy zastosować wartość domyślną podczas tworzenia nowej instancji; w metodzie __init__ obiektu 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) 

Jeśli nie money atrybut jest ustawiony, dodajemy jedną bezpośrednio na podstawie domyślnie skonfigurowany do kolumny.

Należy pamiętać, że wartości domyślne to wyrażeń SQL, a nie wartości Pythona, więc może być konieczne najpierw ich odwzorowanie na obiekty Pythona. Na przykład pole boolowskie będzie mieć domyślną wartość ciągową 'false' lub 'true', a nie obiekt boolowski Python o nazwie False lub .

+2

Więc jeśli chcę wypełnić wszystkie domyślne ustawienia bardziej złożonego obiektu, muszę przerobić na wszystkie kolumny, sprawdzić, czy ma domyślne i wypełnij go odpowiednim atrybutem. Okay, mogę to poprawić. Po prostu zastanawiam się: ta funkcjonalność musi istnieć w sqlalchemy, ponieważ i tak jest potrzebna w czasie wstawiania/aktualizacji. Zastanawiam się, dlaczego nie jest on narażony na działanie użytkowników. – Elrond

+0

@ Elrond: Prawdopodobnie dlatego, że wartości domyślne są skierowane po stronie SQL; możesz mieć niestatyczne wartości domyślne, które są również wyrażone jako SQL. –

+2

Podoba mi się rozwiązanie Martijna, wydaje się bardzo kompletne. Zawsze robiłem tak w przeszłości, co może być nieco mniejszym kodem, ponieważ nie trzeba powtarzać nad kolumnami. http://stackoverflow.com/questions/13384996/how-do-i-set-attribute-default-values-in-sqlalchemy-declarative/13390300#13390300 –

7

Odkryłem mechanizm automatycznego wypełniania niektórych wartości domyślnych po utworzeniu instancji. Przeprowadzam migrację z własnej ORM, która ustawia wartości domyślne podczas tworzenia instancji, więc musiałem zachować to zachowanie i nie chciałem dotykać każdej definicji modelu.

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) 

Głównym ograniczeniem jest to, że obsługiwane są tylko wartości domyślne, które nie podlegają opłacie. Ustawienia domyślne i te, które używają kwerendy bazy danych, wymagają kontekstu wykonania, który nie jest dostępny podczas tworzenia instancji. Ponadto, nie odkryłem przypadku, w którym len(ColumnProperty.columns) != 1, ale to nie jest obsługiwane.

1

Ponieważ muszę domyślne wartości niekoniecznie w konstruktorze, ale czasem z innych miejsc, wpadłem funkcji, które dodałem do mojej klasy bazowej obiektu:

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) 

co oczywiście nie zadziała kalki. Nie mogłem wymyślić, jak to nazwać, a może jest na lepsze (czuć się jak hakowanie myśli już).

Z tego można zrobić coś takiego:

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

Mogę również wywołać metodę nie __init__, ale także z innych metod, w przypadku I tylko trzeba polegać na wartościach w szczególnych okolicznościach (co Skończyło się usunięciem później, ponieważ było zbyt mylące). W niektórych przypadkach może to być bardziej elastyczne niż rozwiązanie @JamesEmerton.

Powiązane problemy