没有ORM,DOM或表单的对象模式/模型

时间:2013-03-28 20:14:14

标签: python json validation serialization orm

我最近使用过MongoEngine。除了MongoDB集成之外,我喜欢明确定义实体结构的想法。字段定义使代码更易于理解。此外,使用这些定义,我可以验证对象以捕获潜在的错误或更准确地序列化/反序列化它们。

MongoEngine的问题在于它专门设计用于存储引擎。这同样适用于Django和SQLAlchemy模型,它们也缺少列表和集合类型。我的问题是,是否存在用于Python的对象模式/模型库,它可以进行自动对象验证和序列化,而不是对象关系映射或任何其他花哨的东西

让我举个例子。

class Wheel(Entity):
    radius = FloatField(1.0)


class Bicycle(Entity):
    front = EntityField(Wheel)
    back = EntityField(Wheel)


class Owner(Entity):
    name = StringField()
    bicycles = ListField(EntityField(Bicycle))


owner = Owner(name='Eser Aygün', bicycles=[])

bmx = Bicycle()
bmx.front = Wheel()
bmx.back = Wheel()

trek = Bicycle()
trek.front = Wheel(1.2)
trek.back = Wheel(1.2)

owner.bicycles.append(bmx)
owner.bicycles.append(trek)

owner.validate()  # checks the structure recursively

给定结构,也很容易序列化和反序列化对象。例如,owner.jsonify()可能会返回字典

{
    'name': 'Eser Aygün',
    'bicycles': [{
        'front': {
            radius: 1.0
        },
        'back': {
            radius: 1.0
        }
    }, {
        'front': {
            radius: 1.2
        },
        'back': {
            radius: 1.2
        }
    }],
}

您可以轻松将其转换回owner.dejsonify(dic)

4 个答案:

答案 0 :(得分:3)

如果有人还在寻找,因为function getFreshValue() { var newVal; $.get('someUrl') .then(function(data) { // Logic that handles inserting the new value // and / or making sure there is a valid value first }); } setInterval(getFreshValue, 7500) // 7.5 second interval 暂时没有更新,那里有一些好的图书馆:

答案 1 :(得分:1)

使用remoteobjects可以实现您所描述的内容,{{3}}包含一种机制(称为dataobject),允许您定义对象的结构,以便可以对其进行验证,它可以是轻松地与JSON进行编组。

它还包含一些用于构建发出HTTP请求的REST客户端库的功能,但不需要使用此部分。

remoteobjects发布版不附带特定的StringFieldIntegerField类型,但实施起来很容易。以下是我维护的代码库中使用BooleanField

的示例remoteobjects
class BooleanField(dataobject.fields.Field):

    def encode(self, value):
        if value is not None and type(value) is not bool:
            raise TypeError("Requires boolean")
        return super(BooleanField, self).encode(value)

然后可以在对象定义中使用它:

class ThingWithBoolean(dataobject.DataObject):
    my_boolean = BooleanField()

然后:

thing = ThingWithBoolean.from_dict({"my_boolean":true})
thing.my_boolean = "hello"
return json.dumps(thing.to_dict()) # will fail because my_boolean is not a boolean

答案 2 :(得分:1)

查看mongopersist,它使用mongo作为Python对象(如ZODB)的持久层。它不执行模式验证,但它允许您透明地在Mongo和Python之间移动对象。

对于验证或其他序列化/反序列化方案(例如表单),请考虑colander。漏勺项目说明:

  

Colander可用作验证和反序列化通过XML,JSON,HTML表单或任何其他同样简单的数据序列化获得的数据的系统。它运行在Python 2.6,2.7和3.2上。漏勺可用于:

     
      
  • 定义数据架构。
  •   
  • 在根据数据模式验证数据结构后,将由字符串,映射和列表组成的数据结构反序列化为任意Python结构。
  •   
  • 将任意Python结构序列化为由字符串,映射和列表组成的数据结构。
  •   

答案 3 :(得分:0)

正如我在评论中所说,我决定发明自己的车轮。我开始实现一个开源Python库, Entities ,这就是我想要的。您可以从https://github.com/eseraygun/python-entities/查看。

该库支持递归和非递归集合类型(列表,集合和字典),嵌套实体和引用字段。它可以为任何复杂的实体自动验证,序列化,反序列化和生成可用密钥。 (事实上​​,de /序列化功能尚未完成。)

这是您使用它的方式:

from entities import *

class Account(Entity):
    id = IntegerField(group=PRIMARY)  # this field is in primary key group
    iban = IntegerField(group=SECONDARY)  # this is in secondary key group
    balance = FloatField(default=0.0)

class Name(Entity):
    first_name = StringField(group=SECONDARY)
    last_name = StringField(group=SECONDARY)

class Customer(Entity):
    id = IntegerField(group=PRIMARY)
    name = EntityField(Name, group=SECONDARY)
    accounts = ListField(ReferenceField(Account), default=list)

# Create Account objects.
a_1 = Account(1, 111, 10.0)  # __init__() recognizes positional arguments
a_2 = Account(id=2, iban=222, balance=20.0)  # as well as keyword arguments

# Generate hashable key using primary key.
print a_1.keyify()  # prints '(1,)'

# Generate hashable key using secondary key.
print a_2.keyify(SECONDARY)  # prints '(222,)'

# Create Customer object.
c = Customer(1, Name('eser', 'aygun'))

# Generate hashable key using primary key.
print c.keyify()  # prints '(1,)'

# Generate hashable key using secondary key.
print c.keyify(SECONDARY)  # prints '(('eser', 'aygun'),)'

# Try validating an invalid object.
c.accounts.append(123)
try:
    c.validate()  # fails
except ValidationError:
    print 'accounts list is only for Account objects'

# Try validating a valid object.
c.accounts = [a_1, a_2]
c.validate()  # succeeds