Meta Class và Thực Hiện ORM
1. Các Lớp Cũng Là Đối Tượng
Trong Python, lớp (class) không chỉ là một khối mã mà còn là một đối tượng thực sự. Điều này có nghĩa là bạn có thể gán lớp cho biến, sao chép nó, thêm thuộc tính vào nó, hoặc truyền nó như một tham số hàm.
Ví dụ:
<div>
<pre>
<code>
class ChuTaoDoiTuong:
pass
doi_tuong = ChuTaoDoiTuong()
print(doi_tuong)
# Output: <__main__.ChuTaoDoiTuong object at 0x...>
def inLop(lop):
print(lop)
inLop(ChuTaoDoiTuong)
# Output: <class '__main__.ChuTaoDoiTuong'>
</code>
</pre>
</div>
2. Tạo Lớp Động
Bạn có thể tạo lớp động trong thời gian chạy bằng cách sử dụng hàm type. Ví dụ:
<div>
<pre>
<code>
def taoLop(ten):
if ten == 'loaiA':
class LoaiA:
pass
return LoaiA
else:
class LoaiB:
pass
return LoaiB
lop = taoLop('loaiA')
print(lop)
# Output: <class '__main__.LoaiA'>
</code>
</pre>
</div>
3. Sử Dụng type Để Tạo Lớp
Hàm type có thể được dùng để tạo lớp với các thông tin như tên lớp, danh sách các lớp cha, và một từ điển chứa các thuộc tính.
<div>
<pre>
<code>
Test = type("Test", (), {})
print(Test())
# Output: <__main__.Test object at 0x...>
</code>
</pre>
</div>
4. Tạo Lớp Với Thuộc Tính Và Phương Thức
Bạn có thể thêm thuộc tính và phương thức vào lớp khi tạo chúng bằng type.
<div>
<pre>
<code>
def hienThiThuocTinh(self):
print(self.thuocTinh)
LopCoPhuongThuc = type('LopCoPhuongThuc', (), {'thuocTinh': True, 'hienThiThuocTinh': hienThiThuocTinh})
doiTuong = LopCoPhuongThuc()
doiTuong.hienThiThuocTinh()
# Output: True
</code>
</pre>
</div>
5. Meta Class Là Gì?
Meta class là "lớp của lớp". Chúng được sử dụng để tạo ra các lớp khác. Ví dụ, type chính là meta class mặc định của Python.
<div>
<pre>
<code>
class LopGoc(object):
__metaclass__ = type # Định nghĩa meta class
class Con(LopGoc):
pass
</code>
</pre>
</div>
6. Sử Dụng Meta Class Để Tạo ORM
ORM (Object-Relational Mapping) giúp ánh xạ giữa đối tượng và cơ sở dữ liệu quan hệ. Một ví dụ đơn giản về việc sử dụng meta class để tạo ORM như sau:
<div>
<pre>
<code>
class MetaclassModel(type):
def __new__(cls, ten_lop, cac_lop_cha, thuoc_tinh):
mapping = {}
for k, v in thuoc_tinh.items():
if isinstance(v, tuple):
mapping[k] = v
for k in mapping.keys():
del thuoc_tinh[k]
thuoc_tinh['__mapping__'] = mapping
thuoc_tinh['__ten_bang__'] = ten_lop
return super().__new__(cls, ten_lop, cac_lop_cha, thuoc_tinh)
class Model(metaclass=MetaclassModel):
def __init__(self, **kwargs):
for ten, gia_tri in kwargs.items():
setattr(self, ten, gia_tri)
def luu(self):
truong = []
gia_tri = []
for k, v in self.__mapping__.items():
truong.append(v[0])
gia_tri.append(getattr(self, k, None))
gia_tri_temp = [str(x) if isinstance(x, int) else f"'{x}'" for x in gia_tri]
cau_lenh_sql = f"INSERT INTO {self.__ten_bang__} ({','.join(truong)}) VALUES ({','.join(gia_tri_temp)})"
print(cau_lenh_sql)
class NguoiDung(Model):
id_nguoi_dung = ('id', 'int unsigned')
ten = ('ten', 'varchar(30)')
email = ('email', 'varchar(30)')
mat_khau = ('mat_khau', 'varchar(30)')
nguoi_dung = NguoiDung(id_nguoi_dung=123, ten='Michael', email='test@orm.org', mat_khau='my-pwd')
nguoi_dung.luu()
# Output: INSERT INTO NguoiDung (id,ten,email,mat_khau) VALUES (123,'Michael','test@orm.org','my-pwd')
</code>
</pre>
</div>
7. Hoàn Thiện Kiểm Tra Loại Dữ Liệu
Có thể cải thiện thêm bằng cách kiểm tra loại dữ liệu trước khi tạo câu lệnh SQL.
<div>
<pre>
<code>
class MetaclassModel(type):
def __new__(cls, ten_lop, cac_lop_cha, thuoc_tinh):
mapping = {}
for k, v in thuoc_tinh.items():
if isinstance(v, tuple):
mapping[k] = v
for k in mapping.keys():
del thuoc_tinh[k]
thuoc_tinh['__mapping__'] = mapping
thuoc_tinh['__ten_bang__'] = ten_lop
return super().__new__(cls, ten_lop, cac_lop_cha, thuoc_tinh)
class Model(metaclass=MetaclassModel):
def __init__(self, **kwargs):
for ten, gia_tri in kwargs.items():
setattr(self, ten, gia_tri)
def luu(self):
truong = []
gia_tri = []
for k, v in self.__mapping__.items():
truong.append(v[0])
gia_tri.append(getattr(self, k, None))
gia_tri_temp = [str(x) if isinstance(x, int) else f"'{x}'" for x in gia_tri]
cau_lenh_sql = f"INSERT INTO {self.__ten_bang__} ({','.join(truong)}) VALUES ({','.join(gia_tri_temp)})"
print(cau_lenh_sql)
class NguoiDung(Model):
id_nguoi_dung = ('id', 'int unsigned')
ten = ('ten', 'varchar(30)')
email = ('email', 'varchar(30)')
mat_khau = ('mat_khau', 'varchar(30)')
nguoi_dung = NguoiDung(id_nguoi_dung=123, ten='Michael', email='test@orm.org', mat_khau='my-pwd')
nguoi_dung.luu()
# Output: INSERT INTO NguoiDung (id,ten,email,mat_khau) VALUES (123,'Michael','test@orm.org','my-pwd')
</code>
</pre>
</div>