Last active
September 28, 2018 07:20
-
-
Save fpagyu/cd42d8a7615232cf0c3f6b24260c302d to your computer and use it in GitHub Desktop.
使用Python的元类实现一个简易orm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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