<p>如果您想要完整的django <code>Model</code>体验,即:</p>
<ul>
<li>用<code>datapoint = MyData(name='johndoe', color='green', ...)</code>创建一个新的特征向量或数据条目,就像django中一样:例如<code>new_user=User(username='johndoe', email='jd@jd.com')</code></li>
<li>使用<code>MyData.objects</code>进行对象管理,如<code>MyData.objects.filter(color__eq='yellow')</code></li>
</ul>
<p>下面是一个关于逻辑的方法。在</p>
<p>首先,您需要一个简单的<code>ObjectManager</code>类:</p>
<pre class="lang-py prettyprint-override"><code>import collections
import operator
import inspect
class ObjectManager(collections.MutableSet):
def __init__(self):
# this will hold a list of all attributes from your custom class, once
# initiated
self._object_attributes = None
self._theset = set()
def add(self, item):
self._theset.add(item)
def discard(self, item):
self._theset.discard(item)
def __iter__(self):
return iter(self._theset)
def __len__(self):
return len(self._theset)
def __contains__(self, item):
try:
return item in self._theset
except AttributeError:
return False
def set_attributes(self, an_object):
self._object_attributes = [
a[0] for a in inspect.getmembers(
an_object, lambda a:not(inspect.isroutine(a))
) if not(a[0].startswith('__') and a[0].endswith('__'))
]
def filter(self, **kwargs):
"""Filters your objects according to one or several conditions
If several filtering conditions are present you can set the
combination mode to either 'and' or 'or'.
"""
mode = kwargs.pop('mode', 'or')
ok_objects = set()
for kw in kwargs:
if '__' in kw:
_kw, op = kw.split('__')
# only allow valid operators
assert op in ('lt', 'le', 'eq', 'ne', 'ge', 'gt')
else:
op = 'eq'
_kw = kw
_oper = getattr(operator, op)
# only allow access to valid object attributes
assert _kw in self._object_attributes
n_objects = (
obj for obj in self
if _oper(getattr(obj, _kw), kwargs[kw])
)
if mode == 'and':
if n_objects:
ok_objects = ok_objects.intersection(n_objects)\
if ok_objects else set(n_objects)
else:
return set()
else:
ok_objects.update(n_objects)
return ok_objects
# feel free to add a `get_or_create`, `create`, etc.
</code></pre>
<p>现在,将该类的一个实例作为属性附加到<code>MyData</code>类,并确保所有新对象都已添加到该类中:</p>
^{pr2}$
<p>现在可以导入向量:</p>
<pre class="lang-py prettyprint-override"><code>DATA = [
{'uid': 1, 'name': 'brad', 'color':'red'},
{'uid': 2, 'name': 'sylvia', 'color':'blue'},
]
for dat in DATA:
myData(**dat)
</code></pre>
<p>或创建新实例:</p>
<pre class="lang-py prettyprint-override"><code>d1 = MyData(uid=10, name='john', color='yellow')
</code></pre>
<p>并利用管理器过滤对象:</p>
<pre class="lang-py prettyprint-override"><code>print([md.name for md in MyData.objects.filter(uid__ge=10)])
# > ['john']
print([md.name for md in MyData.objects.filter(mode='and',uid__ge=1,name__eq='john')])
# > ['john']
print([md.name for md in MyData.objects.filter(mode='or',uid__le=4,name__eq='john')])
# > ['john', 'brad', 'sylvia']
</code></pre>
<hr/>
<p>如果你不想改变这个班,你就不想换了您甚至可以创建一个<code>ObjectManager</code>,它可以在定义或甚至启动某些实例后挂接到任意类(尽管内置类型不起作用)。在</p>
<p>其思想是对目标类的<code>__init__</code>进行monkey修补,并在<code>ObjectManager</code>实例的init上添加<code>objects</code>属性:</p>
<pre class="lang-py prettyprint-override"><code>import gc
import inspect
import collections
import operator
import wrapt # not standard lib > pip install wrapt
class ObjectManager(collections.MutableSet):
def __init__(self, attach_to):
self._object_attributes = None
# add self as class attribute
attach_to.objects = self
# monkey patch __init__ of your target class
@wrapt.patch_function_wrapper(attach_to, '__init__')
def n_init(wrapped, instance, args, kwargs):
wrapped(*args, **kwargs)
c_objects = instance.__class__.objects
if not c_objects:
c_objects.set_attributes(instance)
c_objects.add(instance)
# make sure to be up to date with the existing instances
self._theset = set(obj for obj in gc.get_objects() if isinstance(obj, attach_to))
# already fetch the attributes if instances exist
if self._theset:
self.set_attributes(next(iter(self._theset)))
...
# the rest is identical to the version above
</code></pre>
<p>你现在应该怎么使用它:</p>
<pre class="lang-py prettyprint-override"><code>class MyData:
def __init__(self, uid, name, color):
self.uid = uid
self.name = name
self.color = color
# create some instances
DATA = [
{'uid': 1, 'name': 'brad', 'color':'red'},
{'uid': 2, 'name': 'sylvia', 'color':'blue'},
]
my_datas = []
for dat in DATA:
my_datas.append(myData(**dat)) # appending them just to have a reference
# say that ONLY NOW you decide you want to use an object manager
# Simply do:
ObjectManager(MyData)
# and you are done:
print([md.name for md in MyData.objects.filter(mode='or',uid__le=4,name__eq='john')])
# > ['brad', 'sylvia']
# also any object you create from now on is included:
d1 = MyData(uid=10, name='john', color='yellow')
print([md.name for md in MyData.objects.filter(mode='or',uid__le=4,name__eq='john')])
# > ['brad', 'sylvia', 'john']
</code></pre>