Python元类编程实现DjangoORM

需求说明

使用Python元类编程实现简单的Django Model定义、校验以及构造生成sql语句。

一、定义Field类

我们只定义了两个Field类:IntField、CharField,用于定义Model支持的数据类型以及对值的类型、长度、大小进行一些简单校验。

import numbers

class Field(object):
    def __init__(self):
        self._value = None
    def __str__(self):
        return self._value
    def __get__(self, instance, owner):
        return self._value

class IntField(Field):
    def __init__(self, db_column=None, min_value=None, max_value=None, *args, **kwargs):
        self.db_column = db_column
        if min_value is not None and not isinstance(min_value, numbers.Integral):
            raise ValueError('min_value must be int')
        self.min_value = min_value
        if max_value is not None and not isinstance(max_value, numbers.Integral):
            raise ValueError('max_value must be int')
        self.max_value = max_value
        if min_value is not None and max_value is not None:
            if min_value > max_value:
                raise ValueError('min_value must smaller than max_value')
        super().__init__()

    def __set__(self, instance, value):
        if not isinstance(value, numbers.Integral):
            raise ValueError('IntField value must be int')
        if self.min_value is not None and value < self.min_value:
            raise ValueError(f'IntField value must bigger than {self.min_value}')
        if self.max_value is not None and value > self.max_value:
            raise ValueError(f'IntField value must smaller than {self.max_value}')
        self._value = value


class CharField(Field):
    def __init__(self, db_column=None, max_length=None, *args, **kwargs):
        self.db_column = db_column
        if max_length is not None and not isinstance(max_length, numbers.Integral):
            raise ValueError('max_length must be int')
        elif max_length < 0:
            raise ValueError('max_length must bigger than 0')
        self.max_length = max_length
        super().__init__()

    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError('CharField value must be str')
        if self.max_length is not None and len(value) > self.max_length:
            raise ValueError(f'CharField value length must smaller than {self.max_length}')
        self._value = value
二、定义元类

该元类主要用于将Model中定义的column以及db_table等初始化到Model的实例对象上。

class ModelMetaClass(type):
    def __new__(cls, name, bases, attrs, **kwargs):
        fields = {}
        for key, value in attrs.items():
            if isinstance(value, Field):
                fields[key] = value
        _meta = {}
        attr_meta_class = attrs.get('Meta', None)
        db_table = name.lower()
        if attr_meta_class is not None:
            db_table = getattr(attr_meta_class, 'db_table', db_table)
        _meta['db_table'] = db_table
        attrs['fields'] = fields
        attrs['_meta'] = _meta
        return super().__new__(cls, name, bases, attrs, **kwargs)
三、定义Model基类

Model基类主要用于支持Model创建对象的时候及初始化column值以及定义通用的orm处理逻辑函数。

class BaseModel(metaclass=ModelMetaClass):
    def __init__(self, *args, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        super().__init__()

    def save(self):
        db_table = self._meta.get('db_table')
        fields = []
        values = []
        for key, field in self.fields.items():
            db_column = field.db_column
            if db_column is None:
                db_column = key.lower()
            fields.append(db_column)
            value = getattr(self, key)
            values.append(str(value))
        sql = f"insert {db_table}({','.join(fields)}) value({','.join(values)})"
        print(sql)
四、定义Model实体类
class User(BaseModel):
    name = CharField(max_length=10)
    age = IntField(min_value=0, max_value=100)
    class Meta:
        db_table = 'user'
    def __str__(self):
        return self.name
五、测试
user = User(name='python', age=18)
user.save()

创建model类,以及调用save会输出经过orm转换后的sql语句:
insert user(name,age) value(python,18)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 夜莺2517阅读 127,793评论 1 9
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 12,723评论 28 53
  • 兔子虽然是枚小硕 但学校的硕士四人寝不够 就被分到了博士楼里 两人一间 在学校的最西边 靠山 兔子的室友身体不好 ...
    待业的兔子阅读 7,501评论 2 9
  • 信任包括信任自己和信任他人 很多时候,很多事情,失败、遗憾、错过,源于不自信,不信任他人 觉得自己做不成,别人做不...
    吴氵晃阅读 11,344评论 4 8