python3使用元类和数据描述符实现ORM

# -*- coding: utf-8 -*-
# @Author  : pengj    <ugeg@163.com>
# @Time    : 2019/1/5 16:40
# @File    : MyORM.py
import numbers


class Field:
    pass


class CharField(Field):
    # 数据描述符
    # 好处在于可以在各方法中校验传入值的合理性
    def __init__(self, col_name, max_length):
        if col_name is None or not isinstance(col_name, str):
            raise ValueError("col_name must be given as str")
        if max_length is None or not isinstance(max_length, numbers.Integral):
            raise ValueError("max_length must be given as int")
        self._col_name = col_name
        self._max_length = max_length

    def __get__(self, instance, owner):
        # return getattr(instance, self._col_name)
        return instance.fields[self._col_name]

    def __set__(self, instance, value):
        # 这里如果col_name和数据描述符对应的名字一样的话,如name=CharField(col_name="name",10)
        # 用setattr(instance, self._col_name, value)即user.name=value会再次进入此__set__方法,导致无限递归
        instance.fields[self._col_name] = value


class IntField(Field):
    def __init__(self, col_name, min_length, max_length):
        self._col_name = col_name
        self._min_length = min_length
        self._max_length = max_length

    def __get__(self, instance, owner):
        return instance.fields[self._col_name]

    def __set__(self, instance, value):
        if value is None or (not isinstance(value, numbers.Integral)):
            raise ValueError("value must be given as int")
        instance.fields[self._col_name] = value


class ModelMetaClass(type):
    def __new__(cls, cls_name, base_class, attrs):
        if cls_name == "Model":
            return super().__new__(cls, cls_name, base_class, attrs)
        fields = {}
        for k, v in attrs.items():
            if isinstance(v, Field):
                fields[k] = v
        attrs["fields"] = fields
        _meta = {}
        attrs_meta = attrs.get("Meta", None)
        if attrs_meta is not None and isinstance(attrs_meta, type):
            _meta["tb_name"] = getattr(attrs_meta, "tb_name", cls_name)
            del attrs["Meta"]
        else:
            _meta["tb_name"] = cls_name.lower()
        attrs["_meta"] = _meta
        return super().__new__(cls, cls_name, base_class, attrs)


class Model(metaclass=ModelMetaClass):
    def __init__(self, **kwargs):
        self.fields = {}
        for k, v in kwargs.items():
            setattr(self, k, v)
    # def more_func(self):
    #     pass


class User(Model):
    name = CharField(col_name="name", max_length=10)
    sex = CharField(col_name="sex", max_length=1)
    age = IntField(col_name="age", min_length=1, max_length=10)

    class Meta:
        tb_name = "User"


class Company(Model):
    name = CharField(col_name="name", max_length=10)
    address = CharField(col_name="address", max_length=1)

    # class Meta:
    #     tb_name = "Company"


if __name__ == "__main__":
    user = User(name="boy1", age=5, sex="男")
    user1 = User(name="girl1", age=6, sex="女")
    company = Company(name="com", address="China")
    print(User.__dict__)
    print(user.__dict__)
    print(user1.__dict__)
    print(Company.__dict__)
    print(company.__dict__)

输出

{'__module__': '__main__', 'name': <__main__.CharField object at 0x0000013ACD432828>, 'sex': <__main__.CharField object at 0x0000013ACD432A20>, 'age': <__main__.IntField object at 0x0000013ACD432AC8>, 'fields': {'name': <__main__.CharField object at 0x0000013ACD432828>, 'sex': <__main__.CharField object at 0x0000013ACD432A20>, 'age': <__main__.IntField object at 0x0000013ACD432AC8>}, '_meta': {'tb_name': 'User'}, '__doc__': None}
{'fields': {'name': 'boy1', 'age': 5, 'sex': '男'}}
{'fields': {'name': 'girl1', 'age': 6, 'sex': '女'}}
{'__module__': '__main__', 'name': <__main__.CharField object at 0x0000013ACD432B00>, 'address': <__main__.CharField object at 0x0000013ACD432EB8>, 'fields': {'name': <__main__.CharField object at 0x0000013ACD432B00>, 'address': <__main__.CharField object at 0x0000013ACD432EB8>}, '_meta': {'tb_name': 'company'}, '__doc__': None}
{'fields': {'name': 'com', 'address': 'China'}}

参考:
Python高级编程和异步IO并发编程
Python描述符 (descriptor) 详解-属性查询优先级

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值