2012-01-24 18 views
16

Sử dụng SQLAlchemy ORM, tôi muốn đảm bảo giá trị là đúng loại cho cột của chúng.Làm cách nào để xác minh loại dữ liệu Cột trong SQLAlchemy ORM?

Ví dụ: giả sử tôi có cột Số nguyên. Tôi cố gắng để chèn giá trị "hello", mà không phải là một số nguyên hợp lệ. SQLAlchemy sẽ cho phép tôi làm điều này. Chỉ sau này, khi tôi thực thi session.commit(), nó có tăng ngoại lệ: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"… hay không.

Tôi đang thêm lô bản ghi và tôi không muốn cam kết sau mỗi add(…) đơn lẻ vì lý do hiệu suất.

Vậy làm thế nào tôi có thể:

  • Nâng trừ ngay sau khi tôi làm session.add(…)
  • Hoặc, hãy chắc chắn giá trị Tôi chèn có thể được chuyển đổi sang kiểu dữ liệu mục tiêu Cột, trước thêm nó cho lô?
  • Hoặc bất kỳ cách nào khác để ngăn chặn một bản ghi xấu gây hư hỏng toàn bộ commit().
+0

có thể trùng lặp: http://stackoverflow.com/questions/2390753/is-there-a-way-to-transparently-perform-validation -on-sqlalchemy-objects – greut

+2

@greut Tôi chưa từng thấy câu hỏi đó trước đó, nhưng câu trả lời được đánh giá cao nhất sử dụng một sự phản đối d kỹ thuật. Câu trả lời khác được đưa ra là câu trả lời triết học. Ở đây chúng ta có tác giả của SQLAlchemy với một câu trả lời chính xác và hữu ích. – Nate

Trả lời

27

SQLAlchemy không xây dựng điều này vì nó bảo vệ DBAPI/cơ sở dữ liệu là nguồn xác thực và ép buộc hiệu quả nhất và hiệu quả nhất.

Để xây dựng xác thực của riêng bạn, thường sử dụng xác thực cấp độ xác thực hoặc xác thực cấp ORM. TypeDecorator có lợi thế là nó hoạt động ở lõi và có thể khá trong suốt, mặc dù nó chỉ xảy ra khi SQL thực sự được phát ra.

Để thực hiện xác thực và cưỡng chế sớm hơn, điều này ở cấp ORM.

Validation có thể ad-hoc, ở lớp ORM, qua @validates:

http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators

Hệ thống sự kiện rằng @validates sử dụng cũng có sẵn trực tiếp. Bạn có thể viết một giải pháp tổng quát liên kết xác nhận lựa chọn của bạn cho các loại được ánh xạ:

from sqlalchemy import Column, Integer, String, DateTime 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import event 
import datetime 

Base= declarative_base() 

def validate_int(value): 
    if isinstance(value, basestring): 
     value = int(value) 
    else: 
     assert isinstance(value, int) 
    return value 

def validate_string(value): 
    assert isinstance(value, basestring) 
    return value 

def validate_datetime(value): 
    assert isinstance(value, datetime.datetime) 
    return value 

validators = { 
    Integer:validate_int, 
    String:validate_string, 
    DateTime:validate_datetime, 
} 

# this event is called whenever an attribute 
# on a class is instrumented 
@event.listens_for(Base, 'attribute_instrument') 
def configure_listener(class_, key, inst): 
    if not hasattr(inst.property, 'columns'): 
     return 
    # this event is called whenever a "set" 
    # occurs on that instrumented attribute 
    @event.listens_for(inst, "set", retval=True) 
    def set_(instance, value, oldvalue, initiator): 
     validator = validators.get(inst.property.columns[0].type.__class__) 
     if validator: 
      return validator(value) 
     else: 
      return value 


class MyObject(Base): 
    __tablename__ = 'mytable' 

    id = Column(Integer, primary_key=True) 
    svalue = Column(String) 
    ivalue = Column(Integer) 
    dvalue = Column(DateTime) 


m = MyObject() 
m.svalue = "ASdf" 

m.ivalue = "45" 

m.dvalue = "not a date" 

Validation và ép buộc cũng có thể được xây dựng ở cấp loại sử dụng TypeDecorator, mặc dù điều này chỉ là khi SQL đang được phát ra, chẳng hạn như ví dụ này mà cưỡng ép utf-8 chuỗi để unicode:

http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode

+0

Cảm ơn bạn zzzeek. Tôi đã không sử dụng hệ thống sự kiện trước đây. Ví dụ tuyệt vời cho thấy nơi và làm thế nào để móc vào nó. – Nate

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