Skip to content

Instantly share code, notes, and snippets.

@fpagyu
Last active September 28, 2018 07:20
Show Gist options
  • Save fpagyu/cd42d8a7615232cf0c3f6b24260c302d to your computer and use it in GitHub Desktop.
Save fpagyu/cd42d8a7615232cf0c3f6b24260c302d to your computer and use it in GitHub Desktop.
使用Python的元类实现一个简易orm
import numbers
class Field:
pass
class CharField(Field):
def __init__(self, db_column, max_length: int):
self.db_column = db_column
self._value = ''
if max_length <= 0:
raise ValueError('max_length must be larger than 0')
self.max_length = max_length
def __get__(self, instance, owner):
return self._value
def __set__(self, instance, value):
if value is None:
value = ''
if not isinstance(value, str):
raise ValueError('')
if len(value) > self.max_length:
raise ValueError("value's length must be larger than max_length")
self._value = value
class IntField(Field):
def __init__(self, db_column, min_value: int=None, max_value: int=None):
self.db_column = db_column
self._value = 0
if min_value is not None:
if not isinstance(min_value, numbers.Integral):
raise ValueError("min_value must be int")
if max_value is not None:
if not isinstance(max_value, numbers.Integral):
raise ValueError("max_value must be int")
if min_value is None:
min_value = 0
if max_value is None:
max_value = (1 << 31) - 1
if max_value < min_value:
raise ValueError("max_value must be larger than min_value")
self.min_value = min_value
self.max_value = max_value
def __get__(self, instance, owner):
return self._value
def __set__(self, instance, value:int):
if not isinstance(value, numbers.Integral):
raise ValueError('value must be int')
if value < self.min_value or value > self.max_value:
raise ValueError('')
self._value = value
class MetaModel(type):
def __new__(mcs, name, bases, kwargs):
if name == 'Model':
return super().__new__(mcs, name, bases, kwargs)
fields = {}
for k, v in kwargs.items():
if isinstance(v, Field):
fields[k] = v
attrs_meta = kwargs.get('Meta', None)
_meta = {}
db_table = name.lower()
if attrs_meta is not None:
db_table = getattr(attrs_meta, 'db_table', db_table)
_meta['db_table'] = db_table
kwargs['fields'] = fields
kwargs['_meta'] = _meta
del kwargs['Meta']
return super().__new__(mcs, name, bases, kwargs)
class Model(metaclass=MetaModel):
def __init__(self, *args, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
super().__init__(*args, **kwargs)
def save(self):
pass
class User(Model):
name = CharField(db_column="name", max_length=20)
age = IntField(db_column="age", min_value=1, max_value=200)
class Meta:
db_table = "user"
if __name__ == '__main__':
user = User()
user.name = "fpgayu"
user.age = 26
# user.save()
print(user.fields)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment