Python元类编程实现DjangoORM

时间:2021-6-4 作者:qvyue

需求说明

使用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.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  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)

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。