सबसे पहले, जैसा कि आपको एहसास हुआ, आपको वस्तुओं के भीतर वस्तुओं में परिवर्तनों को ट्रैक करना होगा, क्योंकि SQLAlchemy को आंतरिक वस्तु को बदलने के लिए कोई रास्ता नहीं है। तो, हम एक आधार परिवर्तनशील वस्तु के साथ जिस तरह से हम दोनों के लिए उपयोग कर सकते हैं से बाहर है कि मिल जाएगा:
class MutableObject(Mutable, object):
@classmethod
def coerce(cls, key, value):
return value
def __getstate__(self):
d = self.__dict__.copy()
d.pop('_parents', None)
return d
def __setstate__(self, state):
self.__dict__ = state
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
self.changed()
class Path(MutableObject):
def __init__(self, style, bounds):
super(MutableObject, self).__init__()
self.style = style
self.bounds = bounds
class Bound(MutableObject):
def __init__(self, l, t, r, b):
super(MutableObject, self).__init__()
self.l = l
self.t = t
self.r = r
self.b = b
और हम भी पथ सूची में परिवर्तनों को ट्रैक करने की जरूरत है, इसलिए, हम उस करना है एक उत्परिवर्तनीय वस्तु भी। हालांकि, परिवर्तनशील() विधि को कॉल करते समय म्यूटेबल ट्रैक माता-पिता को प्रचारित करके बदलते हैं, और एसक्यूएलकेकी में वर्तमान कार्यान्वयन केवल एक अनुच्छेद के रूप में असाइन किए गए किसी व्यक्ति को एक अनुच्छेद के रूप में असाइन किया गया है, अनुक्रम की वस्तु के रूप में नहीं, एक शब्दकोश या एक सूची की तरह। यह वह जगह है जहां चीजें जटिल हो जाती हैं।
मुझे लगता है कि सूची आइटम में माता-पिता के रूप में सूची होनी चाहिए, लेकिन यह दो कारणों से काम नहीं करता है: पहला, _parents कमजोर एक कुंजी के लिए एक सूची नहीं ले सकता है, और दूसरा, बदले गए() संकेत शीर्ष पर सभी तरह से प्रचार नहीं करता है, इसलिए, हम केवल सूची को ही बदलकर चिह्नित करेंगे। मुझे 100% यकीन नहीं है कि यह कितना सही है, लेकिन जाने का तरीका सूची के माता-पिता को प्रत्येक आइटम पर असाइन करना प्रतीत होता है, इसलिए जब कोई आइटम बदल जाता है तो समूह ऑब्जेक्ट को flag_modified कॉल मिलता है। यह करना चाहिए।
class MutableList(Mutable, list):
@classmethod
def coerce(cls, key, value):
if not isinstance(value, MutableList):
if isinstance(value, list):
return MutableList(value)
value = Mutable.coerce(key, value)
return value
def __setitem__(self, key, value):
old_value = list.__getitem__(self, key)
for obj, key in self._parents.items():
old_value._parents.pop(obj, None)
list.__setitem__(self, key, value)
for obj, key in self._parents.items():
value._parents[obj] = key
self.changed()
def __getstate__(self):
return list(self)
def __setstate__(self, state):
self[:] = state
हालांकि, यहां एक आखिरी मुद्दा है। माता-पिता को 'लोड' घटना को सुनने के लिए एक कॉल द्वारा असाइन किया जाता है, इसलिए प्रारंभ करने के समय, _parents dict खाली है, और बच्चों को कुछ भी सौंपा नहीं जाता है। मुझे लगता है कि हो सकता है कि लोड लोड ईवेंट को सुनकर आप कुछ क्लीनर तरीका भी कर सकें, लेकिन मुझे लगता है कि आइटम को पुनर्प्राप्त होने पर माता-पिता को पुन: असाइन करना होगा, इसलिए, इसे जोड़ें:
def __getitem__(self, key):
value = list.__getitem__(self, key)
for obj, key in self._parents.items():
value._parents[obj] = key
return value
अंत में, हम पर Group.paths कि MutableList उपयोग करने के लिए:
class Group(BaseModel):
__tablename__ = 'group'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
paths = db.Column(MutableList.as_mutable(types.PickleType))
और यह सब अपने परीक्षण कोड के साथ काम करना चाहिए:
g = Group(name='g1', paths=[Path('blah', Bound(1,1,2,3)),
Path('other_style', Bound(1,1,2,3)),])
session.add(g)
db.session.commit()
g.name = 'g2'
assert g in db.session.dirty
db.session.commit()
g.paths[0].style = 'something else'
assert g in db.session.dirty
सच कहूं, मुझे यकीन है कि यह कैसे सुरक्षित है नहीं कर रहा हूँ जी के लिए यह उत्पादन पर नहीं है, और यदि आपको लचीली स्कीमा की आवश्यकता नहीं है, तो आप शायद पथ और बाउंड के लिए एक टेबल और रिश्तों का उपयोग करके बेहतर होंगे।
शानदार उत्तर, सभी को काम करने के लिए समय निकालने के लिए धन्यवाद - मैं सराहना करता हूं कि यह एक बहुत ही गैर-मानक मामला है। यह सामान्य विचार है कि मुझे लगा कि यह कैसे काम करेगा लेकिन विवरण को समझ में नहीं आया।मुझे इसे वास्तव में समझने के लिए थोड़ा सा अध्ययन करना होगा - जैसा कि आप कहते हैं, शायद इस मार्ग पर जाने का अच्छा विचार भी नहीं है। सूची मुद्दे के आसपास काम करने का आपका विचार बहुत चालाक है, और मुझे यकीन नहीं है कि मैं हिट करता हूं। एक बार फिर धन्यवाद। जब मैं मोबाइल पर नहीं हूं तो आपको इस पर एक उपहार मिलेगा :) –
धन्यवाद। मुझे मदद करने में खुशी है। –
परेशान है कि मैं इस सवाल पर न्यूनतम बक्षीस दे सकता हूं क्योंकि अब मुझे यहां पर इनाम दिया गया था। मैंने पूरी तरह से असंबंधित प्रश्न पर एक बक्षीस शुरू कर दिया है कि मैं आपको 24 घंटे के समय में इनाम देने में सक्षम हूं। –