我的主要课程定义如下:
from pymongo import MongoClient
from credentials import MongoMarketPlaceAuth
client = MongoClient('mongodb://conn_url:conn_port/', ssl=True)
db_connection = client.DB_NAME
db_connection.authenticate(name=MongoMarketPlaceAuth.name, password=MongoMarketPlaceAuth.password)
MarketPlace = db_connection
class MarketPlaceObjects(object):
def __init__(self, collection, fields={}, default_filter={}):
self.collection_name = collection
self.fields = fields
self.default_filter = default_filter
if MarketPlace[collection].count() == 0:
raise Exception('Collection does not exist or has zero objects')
self.objects = MarketPlace[collection]
然后我有一个继承我的主类的类:
class Products(MarketPlaceObjects):
def __init__(self):
super(Products, self).__init__(collection='FlatProduct')
如果这样使用:
from products import Products
p = Products()
p.objects.find_one()
返回描述产品所有方面的字典。 我想做的是弄清楚如何
p.objects.find_one()
它不是返回字典或字典列表,而是返回一个Product对象(来自单个返回的字典)或Product对象列表(来自返回的字典列表)。
我很难过,因为我不确定如何使用自己的Product类包装PyMongo集合类的find_one()或find()方法。
更新(2017-07-25): 这就是我最终做的事情。仍然需要一些优化:
市场的通用类:
class CollectionObjectInstance(object):
def __init__(self, response):
for key, value in response.items():
if isinstance(value, dict):
self.__dict__[key] = CollectionObjectInstance(value)
else:
self.__dict__[key] = value
class CollectionObjectsManager(object):
serializer = CollectionObjectInstance
collection = None
default_projection = {}
default_filter = {}
def __init__(self, **kwargs):
self.__dict__ = kwargs
def find(self, filter={}, projection={}):
filter = self.default_filter.update(filter)
projection = self.default_projection.update(projection)
res = self.collection.find(filter, projection)
for o in res:
yield self.serializer(o)
def find_one(self, filter={}, projection={}):
filter = self.default_filter.update(filter)
projection = self.default_projection.update(projection)
res = self.collection.find_one(filter, projection)
return self.serializer(res)
class MarketPlaceCollection(object):
collection_name = None
serializer = None
objects_manager = CollectionObjectsManager
def __init__(self, *args, **kwargs):
if self.collection_name is None:
raise Exception('collection_name must be defined in class')
if self.serializer is None:
raise Exception('serializer must be defined in class')
collection = MarketPlace[self.collection_name]
if collection.count() == 0:
raise Exception('Collection does not exist or has zero objects')
self.collection = collection
self.objects = self.objects_manager(**self.__dict__, **self.__class__.__dict__)
使用继承的产品实现:
from marketplace import MarketPlaceCollection, CollectionObjectInstance
from settings import BASE_URL
URL_SUFFIX = 'product/'
CASH_PRICE_FEE = 50
LEASE_TERM_WEEKS = 52
class Product(CollectionObjectInstance):
def url(self):
url = BASE_URL + URL_SUFFIX + self.slug
return url
class Products(MarketPlaceCollection):
collection_name = 'FlatProduct'
serializer = Product
答案 0 :(得分:1)
当您致电p.objects
时,您会收到集合列表本身,该行列在self.objects = MarketPlace[collection]
行上。您的Products
无法控制.objects
属性中的方法或属性 - 它是pymongo返回的对象。
因此,要控制Products.objects
的方法和属性,必须使用所需的方法创建另一个类,并在尝试检索Products.objects
时返回该类的对象。 / p>
虽然Python具有"属性"装饰器和描述符协议,以及objects
属性的更复杂的自动化可以使用它们,在这种情况下,它可以以非常简单的方式进行。只需拥有另一个接收集合的类,并通过在其中实现__getattr__
将其他属性代理到集合:
class ObjectList(object):
def __init__(self, collection, cls):
self.collection = collection
self.cls = cls
def find_one(self, *args, **kw):
raw_list = self.collection.find_one(*arg, **kw)
objects = [self.cls(**obj) for obj in raw_list]
return objects[0] if len(objects) == 1 else objects
def __getattr__(self, attr):
"""this is called automatically by Python when a
normal attribute is not found in this object
"""
return getattr(self.collection, attr)
class MarketPlaceObjects(object):
def __init__(self, collection, cls, fields=None, default_filter=None):
self.collection_name = collection
self.fields = fields if fields else {}
self.default_filter = default_filter if defaut_filter else {}
if MarketPlace[collection].count() == 0:
raise Exception('Collection does not exist or has zero objects')
self.objects = ObjectList(MarketPlace[collection], cls)
class Products(MarketPlaceObjects):
def __init__(self):
super(Products, self).__init__(collection='FlatProduct', cls=Product)