2010-06-11 14 views
5

मैं यह समझने की कोशिश कर रहा हूं कि एक साधारण पढ़ने-योग्य संपत्ति के खिलाफ कैसे मानचित्र करें और जब मैं डेटाबेस में सहेजता हूं तो उस संपत्ति को आग लगती है।SQLAlchemy - केवल पढ़ने के लिए (या गणना की गई) संपत्ति के विरुद्ध मानचित्र कैसे करें

एक प्रदूषित उदाहरण को और अधिक स्पष्ट करना चाहिए। सबसे पहले, एक सरल तालिका:

meta = MetaData() 
foo_table = Table('foo', meta, 
    Column('id', String(3), primary_key=True), 
    Column('description', String(64), nullable=False), 
    Column('calculated_value', Integer, nullable=False), 
    ) 

मुझे क्या करना केवल पढ़ने के लिए संपत्ति के साथ एक वर्ग है कि मेरे लिए calculated_value स्तंभ में सम्मिलित होगा जब मैं session.commit (फोन की स्थापना की है चाहता हूँ) ...

import datetime 
def Foo(object): 
    def __init__(self, id, description): 
     self.id = id 
     self.description = description 

    @property 
    def calculated_value(self): 
     self._calculated_value = datetime.datetime.now().second + 10 
     return self._calculated_value 

SQLAlchemy डॉक्स के अनुसार, मुझे लगता है कि मैं तो इस तरह के नक्शे करना चाहिए:

mapper(Foo, foo_table, properties = { 
    'calculated_value' : synonym('_calculated_value', map_column=True) 
    }) 

इस के साथ समस्या यह है कि _calculated_ है मान तब तक कोई नहीं है जब तक कि आप गणना की गई_अल्यू संपत्ति तक नहीं पहुंच जाते। ऐसा लगता है कि SQLAlchemy डेटाबेस में सम्मिलन पर संपत्ति को कॉल नहीं कर रहा है, इसलिए मुझे इसके बजाय कोई भी मूल्य नहीं मिल रहा है। इसे मैप करने का सही तरीका क्या है ताकि "गणना_value" संपत्ति का परिणाम foo तालिका के "गणना_value" कॉलम में डाला गया हो?

ठीक है - अगर किसी और के पास एक ही प्रश्न है तो मैं इस पोस्ट को संपादित कर रहा हूं। मैं जो कर रहा था वह मैपर एक्सटेंशन का उपयोग कर रहा था। मुझे विस्तार के उपयोग के साथ आपको एक बेहतर उदाहरण दें:

class UpdatePropertiesExtension(MapperExtension): 
    def __init__(self, properties): 
     self.properties = properties 

    def _update_properties(self, instance): 
     # We simply need to access our read only property one time before it gets 
     # inserted into the database. 
     for property in self.properties: 
      getattr(instance, property) 

    def before_insert(self, mapper, connection, instance): 
     self._update_properties(instance) 

    def before_update(self, mapper, connection, instance): 
     self._update_properties(instance) 

और इस तरह आप इसका उपयोग करते हैं। आइए मान लें कि आपके पास कई कक्षाओं के साथ एक वर्ग है जो केवल डेटाबेस को सम्मिलित करने से पहले आग लगाना चाहिए। मैं यहां मान रहा हूं कि इनमें से प्रत्येक के लिए केवल गुणों को पढ़ा गया है, आपके पास डेटाबेस में एक समान कॉलम है जिसे आप संपत्ति के मूल्य के साथ पॉप्युलेट करना चाहते हैं। तुम अब भी प्रत्येक प्रॉपर्टी के लिए एक पर्याय स्थापित करने के लिए जा रहे हैं, लेकिन आप इसके बाद के संस्करण जब आप वस्तु के नक्शे नक्शाकार एक्सटेंशन का उपयोग:

class Foo(object): 
    def __init__(self, id, description): 
     self.id = id 
     self.description = description 
     self.items = [] 
     self.some_other_items = [] 

    @property 
    def item_sum(self): 
     self._item_sum = 0 
     for item in self.items: 
      self._item_sum += item.some_value 
     return self._item_sum 

    @property 
    def some_other_property(self): 
     self._some_other_property = 0 
     .... code to generate _some_other_property on the fly.... 
     return self._some_other_property 

mapper(Foo, metadata, 
    extension = UpdatePropertiesExtension(['item_sum', 'some_other_property']), 
    properties = { 
     'item_sum' : synonym('_item_sum', map_column=True), 
     'some_other_property' : synonym('_some_other_property', map_column = True) 
    }) 

उत्तर

1

मुझे यकीन है कि इसे प्राप्त करने के लिए आप क्या sqlalchemy.orm का उपयोग कर चाहते हैं संभव है नहीं कर रहा हूँ। पर्याय। उचित रूप से इस तथ्य को नहीं दिया गया कि कैसे स्क्लेल्चेमी ट्रैक रखती है कि कौन से उदाहरण गंदे हैं और फ्लश के दौरान अपडेट होने की आवश्यकता है।

(env)[email protected]:~/stackoverflow$ cat stackoverflow.py 

engine_string = '' 

from sqlalchemy import Table, Column, String, Integer, MetaData, create_engine 
import sqlalchemy.orm as orm 
import datetime 

engine = create_engine(engine_string, echo = True) 
meta = MetaData(bind = engine) 

foo_table = Table('foo', meta, 
    Column('id', String(3), primary_key=True), 
    Column('description', String(64), nullable=False), 
    Column('calculated_value', Integer, nullable=False), 
) 

meta.drop_all() 
meta.create_all() 

class MyExt(orm.interfaces.SessionExtension): 
    def before_commit(self, session): 
     for obj in session: 
      if isinstance(obj, Foo): 
       obj.calculated_value = datetime.datetime.now().second + 10 

Session = orm.sessionmaker(extension = MyExt())() 
Session.configure(bind = engine) 

class Foo(object): 
    def __init__(self, id, description): 
     self.id = id 
     self.description = description 

orm.mapper(Foo, foo_table) 

(env)[email protected]:~/stackoverflow$ ipython 
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26) 
Type "copyright", "credits" or "license" for more information. 

IPython 0.10 -- An enhanced Interactive Python. 
?   -> Introduction and overview of IPython's features. 
%quickref -> Quick reference. 
help  -> Python's own help system. 
object? -> Details about 'object'. ?object also works, ?? prints more. 

In [1]: from stackoverflow import * 
2010-06-11 13:19:30,925 INFO sqlalchemy.engine.base.Engine.0x...11cc select version() 
2010-06-11 13:19:30,927 INFO sqlalchemy.engine.base.Engine.0x...11cc {} 
2010-06-11 13:19:30,935 INFO sqlalchemy.engine.base.Engine.0x...11cc select current_schema() 
2010-06-11 13:19:30,936 INFO sqlalchemy.engine.base.Engine.0x...11cc {} 
2010-06-11 13:19:30,965 INFO sqlalchemy.engine.base.Engine.0x...11cc select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and lower(relname)=%(name)s 
2010-06-11 13:19:30,966 INFO sqlalchemy.engine.base.Engine.0x...11cc {'name': u'foo'} 
2010-06-11 13:19:30,979 INFO sqlalchemy.engine.base.Engine.0x...11cc 
DROP TABLE foo 
2010-06-11 13:19:30,980 INFO sqlalchemy.engine.base.Engine.0x...11cc {} 
2010-06-11 13:19:30,988 INFO sqlalchemy.engine.base.Engine.0x...11cc COMMIT 
2010-06-11 13:19:30,997 INFO sqlalchemy.engine.base.Engine.0x...11cc select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and lower(relname)=%(name)s 
2010-06-11 13:19:30,999 INFO sqlalchemy.engine.base.Engine.0x...11cc {'name': u'foo'} 
2010-06-11 13:19:31,007 INFO sqlalchemy.engine.base.Engine.0x...11cc 
CREATE TABLE foo (
     id VARCHAR(3) NOT NULL, 
     description VARCHAR(64) NOT NULL, 
     calculated_value INTEGER NOT NULL, 
     PRIMARY KEY (id) 
) 


2010-06-11 13:19:31,009 INFO sqlalchemy.engine.base.Engine.0x...11cc {} 
2010-06-11 13:19:31,025 INFO sqlalchemy.engine.base.Engine.0x...11cc COMMIT 

In [2]: f = Foo('idx', 'foo') 

In [3]: f.calculated_value 

In [4]: Session.add(f) 

In [5]: f.calculated_value 

In [6]: Session.commit() 
2010-06-11 13:19:57,668 INFO sqlalchemy.engine.base.Engine.0x...11cc BEGIN 
2010-06-11 13:19:57,674 INFO sqlalchemy.engine.base.Engine.0x...11cc INSERT INTO foo (id, description, calculated_value) VALUES (%(id)s, %(description)s, %(calculated_value)s) 
2010-06-11 13:19:57,675 INFO sqlalchemy.engine.base.Engine.0x...11cc {'description': 'foo', 'calculated_value': 67, 'id': 'idx'} 
2010-06-11 13:19:57,683 INFO sqlalchemy.engine.base.Engine.0x...11cc COMMIT 

In [7]: f.calculated_value 
2010-06-11 13:20:00,755 INFO sqlalchemy.engine.base.Engine.0x...11cc BEGIN 
2010-06-11 13:20:00,759 INFO sqlalchemy.engine.base.Engine.0x...11cc SELECT foo.id AS foo_id, foo.description AS foo_description, foo.calculated_value AS foo_calculated_value 
FROM foo 
WHERE foo.id = %(param_1)s 
2010-06-11 13:20:00,761 INFO sqlalchemy.engine.base.Engine.0x...11cc {'param_1': 'idx'} 
Out[7]: 67 

In [8]: f.calculated_value 
Out[8]: 67 

In [9]: Session.commit() 
2010-06-11 13:20:08,366 INFO sqlalchemy.engine.base.Engine.0x...11cc UPDATE foo SET calculated_value=%(calculated_value)s WHERE foo.id = %(foo_id)s 
2010-06-11 13:20:08,367 INFO sqlalchemy.engine.base.Engine.0x...11cc {'foo_id': u'idx', 'calculated_value': 18} 
2010-06-11 13:20:08,373 INFO sqlalchemy.engine.base.Engine.0x...11cc COMMIT 

In [10]: f.calculated_value 
2010-06-11 13:20:10,475 INFO sqlalchemy.engine.base.Engine.0x...11cc BEGIN 
2010-06-11 13:20:10,479 INFO sqlalchemy.engine.base.Engine.0x...11cc SELECT foo.id AS foo_id, foo.description AS foo_description, foo.calculated_value AS foo_calculated_value 
FROM foo 
WHERE foo.id = %(param_1)s 
2010-06-11 13:20:10,481 INFO sqlalchemy.engine.base.Engine.0x...11cc {'param_1': 'idx'} 
Out[10]: 18 

SessionExtensions पर अधिक:: sqlalchemy.orm.interfaces.SessionExtension -

लेकिन वहाँ अन्य तरीके से आप इस कार्यक्षमता कैसे प्राप्त कर सकते है SessionExtensions (ऊपर भरे जाने की जरूरत है कि कम से engine_string चर नोटिस)।

+1

दिलचस्प।भले ही मैंने इसे थोड़ा अलग तरीके से हल किया, मैंने इसे उत्तर के रूप में चिह्नित किया क्योंकि इसे काम करना चाहिए। जितना अधिक मैं स्क्लाक्लेमी के बारे में सीखता हूं, उतना ही मुझे यह पसंद है! –

5

आपके उत्तर के साथ संपादन के लिए धन्यवाद, जेफ। मेरे पास एक ही समस्या थी और इसे आपके कोड का उपयोग करके हल किया गया था, यहां घोषणात्मक आधार का उपयोग करने वालों के लिए कुछ ऐसा ही है। आप कुछ ही मिनटों बचाने नक्शाकार तर्क और समानार्थी निर्दिष्ट करने का तरीका को देख सकता है: SQLAlchemy समर्थन कुछ हाइब्रिड गुण कहा जाता है, जो आप डीबी को परिकलित मानों को बचाने के लिए निर्धारक के रूप में तरीकों को परिभाषित करते हैं की

from sqlalchemy.ext.declarative import declarative_base 

class Users(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    _calculated_value = Column('calculated_value', String) 

    __mapper_args__ = {'extension': UpdatePropertiesExtension(['calculated_value'])} 

    def __init__(self, name): 
    self.name = name 

    @property 
    def calculated_value(self): 
    self._calculated_value = "foobar" 
    return self._calculated_value 

    calculated_value = synonym('_calculated_value', descriptor=calculated_value) 
+0

धन्यवाद! वास्तव में मुझे कुछ समय बचाया। –

0

नए संस्करणों।

मुझे यकीन नहीं है कि मैं उस समस्या को समझता हूं जिसे आप उदाहरण कोड देने के लिए पर्याप्त हल करने की कोशिश कर रहे हैं, लेकिन Google के माध्यम से इस पर फंसे हुए किसी भी व्यक्ति के लिए यहां पोस्ट करना।

संबंधित मुद्दे