2012-12-09 14 views
13

Tôi có một mô hình khai báo-base:Làm thế nào để áp dụng giá trị mặc định cột trước một cam kết trong SQLAlchemy

class User(Base): 
    id = Column(Integer, primary_key=True) 
    money = Column(Integer, default=100) 

và sau đó tôi chạy

>>> u = User() 
>>> u.money 
None 

Làm thế nào tôi có thể cư giá trị mặc định sử dụng SQLAlchemy mà không viết bất cứ thứ gì vào cơ sở dữ liệu?

+0

Xem thêm: https://stackoverflow.com/a/48097586/6646912 – krassowski

Trả lời

13

Cột mặc định chỉ áp dụng cho các câu lệnh INSERT và UPDATE và do đó không được áp dụng cho đến khi bạn .flush() phiên.

Để xem cùng một giá trị trên các phiên bản mới trước khi bạn tuôn ra, bạn cần áp dụng mặc định khi tạo một cá thể mới; trong phương pháp __init__ của đối tượng 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) 

Nếu không money thuộc tính đang được thiết lập, chúng tôi thêm một trực tiếp dựa trên cấu hình mặc định cho cột.

Lưu ý rằng các giá trị mặc định là Biểu thức SQL, không phải giá trị Python, vì vậy bạn có thể phải ánh xạ các giá trị đó cho các đối tượng Python trước tiên. Ví dụ: trường boolean sẽ có giá trị chuỗi 'false' hoặc 'true' mặc định, không phải là một đối tượng boolean Python False hoặc True Python.

+2

Vì vậy, nếu tôi muốn điền vào tất cả các giá trị mặc định của một đối tượng phức tạp hơn, tôi phải lặp qua tất cả các cột, xem nó có mặc định hay không điền nó vào thuộc tính tương ứng. Được rồi, tôi có thể viết mã đó lên. Tôi chỉ tự hỏi: Chức năng này phải tồn tại trong sqlalchemy, bởi vì nó cần nó lúc chèn/cập nhật thời gian anyway. Và tôi tự hỏi, tại sao nó không tiếp xúc với người dùng. – Elrond

+0

@Elrond: Có lẽ vì các giá trị mặc định được nhắm vào phía SQL; bạn có thể có các giá trị mặc định không tĩnh được biểu diễn dưới dạng SQL. –

+2

Tôi thích giải pháp của Martijn, có vẻ rất hoàn chỉnh. Tôi đã luôn luôn thực hiện nó như thế này trong quá khứ, mà có thể là một chút ít mã như bạn không cần phải lặp qua các cột của bạn. http://stackoverflow.com/questions/13384996/how-do-i-set-attribute-default-values-in-sqlalchemy-declarative/13390300#13390300 –

7

Tôi đã phát hiện ra một cơ chế để tự động điền một số mặc định khi tạo một cá thể. Tôi đang di chuyển từ một ORM nội bộ để thiết lập mặc định khi tạo cá thể, vì vậy tôi cần phải bảo toàn hành vi này và tôi không muốn chạm vào mọi định nghĩa mô hình.

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) 

Giới hạn chính là chỉ các giá trị mặc định không thể gọi được hỗ trợ. Các giá trị mặc định có thể gọi và những người sử dụng truy vấn cơ sở dữ liệu yêu cầu ngữ cảnh thực thi không có sẵn tại thời gian tạo cá thể. Ngoài ra, tôi đã không phát hiện ra một trường hợp mà len(ColumnProperty.columns) != 1 nhưng cũng không được hỗ trợ.

1

Vì tôi cần các giá trị mặc định không nhất thiết phải ở nhà xây dựng, nhưng đôi khi từ các nơi khác, tôi đã đưa ra một chức năng, mà tôi thêm vào lớp cơ sở Object tôi:

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) 

Mà rõ ràng không làm việc cho cuộc gọi. Tôi không thể tìm ra cách để gọi nó, và có lẽ nó cho tốt hơn (cảm thấy như hack các suy nghĩ đã).

Với điều này tôi có thể làm một cái gì đó như:

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

Tôi cũng có thể gọi phương thức không __init__, mà còn từ các phương pháp khác, trong trường hợp tôi chỉ cần phải dựa vào các giá trị trong trường hợp đặc biệt (mà Tôi đã kết thúc việc xóa sau, vì nó quá khó hiểu). Tuy nhiên trong một số trường hợp, điều này có thể linh hoạt hơn so với giải pháp của @JamesEmerton.

Các vấn đề liên quan