2012-12-22 16 views
23

हाल ही में मैं पता लगा कि SQLAlchemy स्तम्भ डिफ़ॉल्ट के रूप में मैं इसे करने की उम्मीद काम नहीं करता:ऑब्जेक्ट प्रतिबद्ध होने से पहले SQLAlchemy डिफ़ॉल्ट कॉलम मान क्यों उपलब्ध नहीं है?

>>> Base = declarative_base() 
>>> class TestModel(Base): 
    ...     __tablename__ = 'tmodel' 
...     id = sa.Column(sa.Integer, primary_key=True) 
...     foo = sa.Column(sa.Integer, default=0) 
...     
>>> tmodel_instance = TestModel() 
>>> print tmodel_instance.foo 
None 
>>> session.add(tmodel_instance) 
>>> print tmodel_instance.foo 
None 
>>> session.commit() 
>>> print tmodel_instance.foo 
0 

मैं tmodel_instance.foo चाहते सही वस्तु इन्स्टेन्शियशन के बाद 0 बराबर करने के लिए, लेकिन यह जब क्रियान्वित करने लगता है कि डिफ़ॉल्ट मान ही प्रयोग किया जाता है INSERT कमांड, और यह वास्तव में मुझे भ्रमित करता है। defaultserver_default से अधिक क्यों पसंद करेंगे? और मैं जो चाहता हूं उसे कैसे प्राप्त करूं? क्या मुझे __init__ में सभी डिफ़ॉल्ट तर्क निर्दिष्ट करना है? ऐसा लगता है कि कोड डुप्लिकेशंस है: डिफ़ॉल्ट मान बदलने के लिए मुझे इसे दो बार बदलना है और उन मानों को समानता बनाए रखना है - क्या इससे बचने का कोई तरीका है?

+2

+1 सहमत हूँ। यह समझ में नहीं आता है कि किसी ऑब्जेक्ट को बनाए रखने का कार्य इसके गुणों को बदल देगा। –

उत्तर

14

एक चार में से एक कारणों के लिए सर्वर डिफ़ॉल्ट से अधिक डिफ़ॉल्ट पसंद करेंगे:

  1. आप एक अजगर समारोह, नहीं किसी SQL समारोह, डिफ़ॉल्ट के लिए (या किसी SQL अभिव्यक्ति है कि कुछ की जरूरत है चलाना चाहते हैं प्रति-आईएनएसईआरटी पायथन राज्य भी)।

  2. डिफ़ॉल्ट प्राथमिक कुंजी कॉलम का हिस्सा है। ओआरएम प्राथमिक कुंजी के बिना एक पंक्ति वापस लोड नहीं कर सकता है, इसलिए ORM का उपयोग करते समय server_default आमतौर पर पीके कॉलम के लिए उपयोगी नहीं होता है।

  3. SQL अभिव्यक्ति जिसे आप चलाने के लिए चाहते हैं डेटाबेस को "सर्वर डिफ़ॉल्ट" के रूप में समर्थित नहीं है।

  4. आप एक स्कीमा से निपट रहे हैं जिसे आप बदलना नहीं चाहते/नहीं बदल सकते हैं।

इस मामले में, जब आप "foo" डेटाबेस आपरेशन के अपने आवेदन स्वतंत्र में "0" होना चाहते हैं, विकल्प हैं:

  1. उपयोग __init__()। यह अजगर है!

  2. घटनाओं का उपयोग करें।

यहाँ __init__() है:

class TestModel(Base): 
    # ... 

    def __init__(self): 
     self.foo = 0 

यहाँ घटनाओं है (विशेष रूप से init event):

from sqlalchemy import event 

@event.listens_for(Foo, "init") 
def init(target, args, kwargs): 
    target.foo = 0 
+3

लेकिन एसक्यूएलकेमी मॉडल इस तरह से क्यों डिजाइन किए गए थे: सृजन के बाद सही मूल्य के बजाय कोई नहीं? यह निश्चित रूप से उन लोगों को भ्रमित करता है जो अन्य ओआरएम पुस्तकालयों में उपयोग किए जाते हैं – d9k

+3

"डिफ़ॉल्ट" अक्सर SQL अभिव्यक्ति या पूर्ण उड़ा सर्वर-साइड मान से अधिक नहीं होता है।यह तब तक ज्ञात नहीं हो सकता जब तक कि INSERT नहीं होता है, या ऑब्जेक्ट बनने पर अजीब रूप से पूर्व-निष्पादित होने पर बहुत कम आदर्श होता है (जो स्वयं मान को वास्तविक "INSERT defaut" से कम करता है)। इसलिए कोर-स्तरीय डालने वाले डिफ़ॉल्टों का केवल एक सबसेट बनाने के लिए पूरी तरह से अलग-अलग कार्य असंगत होगा। – zzzeek

4

आप चूक को भरने के लिए init घटना का उपयोग कर सकते हैं। यह ईवेंट श्रोता यह करना होगा:

from sqlalchemy import event 
from sqlalchemy.orm import mapper 
from sqlalchemy.inspection import inspect 


def instant_defaults_listener(target, args, kwargs): 
    for key, column in inspect(target.__class__).columns.items(): 
     if column.default is not None: 
      if callable(column.default.arg): 
       setattr(target, key, column.default.arg(target)) 
      else: 
       setattr(target, key, column.default.arg) 


event.listen(mapper, 'init', instant_defaults_listener) 
2

आप sqlalchemy_utils से force_instant_defaults श्रोता उपयोग कर सकते हैं इस व्यवहार को बदलने के लिए:

from sqlalchemy_utils import force_instant_defaults 

force_instant_defaults() 

class TestModel(Base): 
    __tablename__ = 'tmodel' 
    id = sa.Column(sa.Integer, primary_key=True) 
    foo = sa.Column(sa.Integer, default=0) 

model = TestModel() 
assert model.foo == 0 
संबंधित मुद्दे