仿优酷项目

一、ORM介绍

对象关系映射,把数据库中的表数据(表名、表记录、字段)全部映射到python中。

​ mysql: python:

​ 表名 ————>类名

​ 记录 ————>对象

​ 字段 ————>对象.属性

第一步:写字段类型的类

	--字段名
​ --字段类型(长度)
​ --varchar(256)
​ --int
​ --是否为主键
​ --默认值 ​ 仿优酷中使用的字段类型:
​ —int
​ —string

第二步:写表类

		User:  #用户表
​ user_name
​ pwd ​ Movie: #电影表
​ movie_name
​ movie_size ​ Notice: #公告表
​ title
​ content

接下来我们解决三个问题:

问题1: 假设100张表就需要写100个__init__。
解决:
继承一个Models父类 问题2: 每张表的字段名与字段数量不同,导致无法直接继承Models父类
解决:
dict是对象,继承dict,触发字典内部的__init__(可接受任意数量以及任意类型属性) 问题3: 字典的取/存值方式有限,希望改为 对象.属性取值, 对象.属性=值 存值的方式。
解决:
__getattr__: 取值方式
__setattr__: 存值方式

第三步:表的约束

问题: 让所有的表类都遵循以下约束
- 表名
- 必须要有一个唯一主键
- 表的字段 解决:通过元类去控制类的创建,使其遵循以上约束.

第四步:

 - 表名
- 必须要有一个唯一主键
- 表的字段

接下来就开始我们的代码之旅吧!!!

***************************mysql_control.py******************************
import pymysql class MySQL:
#接下来是一个单例模式,因为每定义一个函数都要实例化mysql_control.MySQL()
__instance = None #隐藏 def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance def __init__(self):
#创建数据库连接
self.mysql = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user= 'root',
password = '12345678',
database = 'yjy',
charset ='utf8',
autocommit = True
) #获取游标
self.cursor = self.mysql.cursor(
pymysql.cursors.DictCursor
) #查看
def select(self,sql,args=None):
self.cursor.execute(sql,args) #提交select语句 #获取查询结果
res = self.cursor.fetchall()
return res #提交
def execute(self,sql,args):
try:
# insert into table(name, pwd) values('yjy', '123');
self.cursor.execute(sql,args) except Exception as e:
print(e) def close(self):
self.cursor.close() #关闭游标
self.mysql.close() #关闭连接对象mysql
***************************orm.py******************************
'''
需求:
创建一张User表,表内字段(id,name,pwd)
'''
# class User: #先定义一个User类,即创建User表,orm的特性就是将表名映射成类名
# def __init__(self,id,name,password):
# self.id = id
# self.name = name
# self.password = password import mysql_control
'''第一步:写字段类型类'''
#父类
# 定义这个父类的关键就在于把各个类中相同的东西拿出来,减小代码冗余
class Field:
def __init__(self,name,column_type,primary_key,default):
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default = default # int类型
class IntegerField(Field): #继承父类
def __init__(self,name,column_type= "int",primary_key=False,default=0):
super().__init__(name,column_type,primary_key,default) #继承父类中的这些方法 #string varchar() 类型
class StringField(Field):
def __init__(self,name,column_type= "varchar(256)",primary_key= False,default = None):
super().__init__(name,column_type,primary_key,default) '''第三步,第四步:通过元类进行表的约束''' class OrmMetaClass(type):
def __new__(cls, class_name, class_base, class_attr):
# 接收Models类的东西、User类的东西
# print(class_name, class_base, class_attr) # (类名、父类、类的名称空间)
# print(class_attr) if class_name == "Models":
return type.__new__(cls, class_name, class_base, class_attr) # 若不是Models则开始控制类的创建
# 1.表名 若table_name没有,则取class_name
table_name = class_attr.get('table_name', class_name) # 表的名字 mappings = {} # 在python中返回的表,它是以;列表套字典的形式 primary_key = None # 2.约束必须有一个唯一的主键
for k, v in class_attr.items():
# print(k, v) # user_id, IntegerField(name='user_id', primary_key=True)
if isinstance(v, Field):
# 3.获取所有字段,把所有表的字段都封装到一个独立的字典中mappings
mappings[k] = v if v.primary_key: # 如果字段有主键 # 判断是否有多个主键
if primary_key:
raise TypeError('只能有一个主键') # 给他跑一个异常 primary_key = v.name
# 剔除原表类的名称空间中重复的字段属性,目的是为了减少内存的占用
for k in mappings.keys():
class_attr.pop(k)
# 如果没有主键
if not primary_key:
raise TypeError('必须要有一个主键') class_attr['table_name'] = table_name
# select * from self.table_name where id=self.primary_key。
class_attr['primary_key'] = primary_key
# insert into self.table_name(字段名, ...) values (字段对象.值)
class_attr['mappings'] = mappings # {'字段名': '字段对象'}
# print(class_attr)
return type.__new__(cls, class_name, class_base, class_attr) # 解决100张表就需要写100个__init__的问题
class Models(dict, metaclass=OrmMetaClass):
# 继承dict解决的是每张表的字段名与字段数量不同,导致无法直接继承Models父类
# 继承dict,触发字典内部的__init__(可接受任意数量以及任意类型属性
def __init__(self, **kwargs): # **kwargs就是id,name,pwd 'name': 'yjy' --- > name=yjy
super().__init__(**kwargs) def __getattr__(self, item):
# 将 字典[key]的取值方式转换为---> 字典.key的取值方式
return self.get(item) def __setattr__(self, key, value):
# 将字典的赋值方式转变为对象.属性的方式
self[key] = value # 查看
@classmethod
def select(cls, **kwargs): # name= 'yjy',pwd= '123'
mysql_obj = mysql_control.MySQL()
if not kwargs:
# 拼接select查询语句
sql = 'select * from %s' % cls.table_name res = mysql_obj.select(sql) # sql(查询条件):select * from User where name = yjy;
else:
key = list(kwargs.keys())[0] # data_name
value = kwargs.get(key) # yjy
# 拼接select查询语句
sql = 'select * from %s where %s =?' % (cls.table_name, key)
# 防止sql注入
sql = sql.replace('?', '%s')
# 提交sql,并返回查询结果
res = mysql_obj.select(sql, value) # cls(**{key:value}) ---> cls(key=value) --> obj # 把列表套字典 ---> 列表套对象
return [cls(**r) for r in res] # [{}, {}, {}] ---> [obj, obj, obj..] # 插入
def save(self):
mysql = mysql_control.MySQL()
# sql: insert into table(name, pwd..) values('yjy', '123', ...);
# sql: insert into table(name, pwd..) values(?,?,?); # 获取所有的字段名
fields = [] # 他是一个列表,我们需要用','.join() 拼接起来 # 获取字段对应的值
values = [] # 替换条件
replace = [] # [?,?]
for k, v in self.mappings.items():
# print(k, v) # user_id = IntegerField(name='user_id', primary_key=True)
fields.append(k) # k == v.name
values.append(getattr(self, v.name, v.default)) # getattr(User(), v.name) --> 字段值
replace.append('?') # [?, ?, ?...] # insert into user_info(user_id,user_name,pwd) values(?,?,?)
sql = 'insert into %s(%s) values(%s)' % (self.table_name, ','.join(fields), ','.join(replace))
sql = sql.replace('?', '%s') # 防止sql注入
mysql.execute(sql, values) # 提交sql语句 # 更新
def sql_update(self):
'''默认使用主键当做更新的查询条件'''
mysql = mysql_control.MySQL() # 获取字段名
fields = [] # 获取字段名
values = [] # 获取主键的值
primary_key = None # name=yjy, pwd='123'
for k, v in self.mappings.items():
if v.primary_key:
# 通过反射获取主键的值
primary_key = getattr(self, v.name) else:
fields.append(v.name + '=?') # [name=?, pwd=?]
# 通过反射获取修改字段的值
values.append(
getattr(self, v.name)
) # sql: update user_info set name=yjy, pwd='123' where user_id=1;
# sql: update user_info set name=?, pwd=? where user_id=1;
sql = 'update %s set %s where %s=%s' % (self.table_name, ','.join(fields), self.primary_key, primary_key)
sql = sql.replace('?', '%s')
mysql.execute(sql, values) '''第二步:创建表类'''
class User(Models): #Models中已经有表的字段,所以在这里直接继承就好了
# 自定义表名
table_name = 'user_info' # {'table_name': 'user_info'}
# id, name, pwd
user_id = IntegerField(name='user_id',primary_key=True)
user_name = StringField(name='user_name')
pwd = StringField(name='pwd') #注意:我们要在数据库中创建下面这样一张表
'''
create table user_info(
user_id int primary key auto_increment,
user_name varchar(256),
pwd varchar(256));
''' class Movie(Models):
pass class Notice(Models):
pass if __name__ == '__main__':
obj = User(user_name='yjy')
obj.save() #插入数据 user_obj = User.select(user_name='yjy')[0] #查看数据数据
print(user_obj) ##{'user_id': 1, 'user_name': 'yjy', 'pwd': None}
print(user_obj.user_name) #yjy user_obj.user_name = 'yjyyjyyjy'
user_obj.sql_update()
print(user_obj.user_name) #yjyyjyyjy #数据库中结果
+---------+-----------+------+
| user_id | user_name | pwd |
+---------+-----------+------+
| 1 | yjyyjyyjy | NULL |
+---------+-----------+------+

仿优酷项目—orm的更多相关文章

  1. ViewPager实现滑屏切换页面及动画效果(仿优酷客户端)

     找了许多实现该功能的例子,但效果都不很理想,于是自己结合网上的资源及自己的总结,整理了一下,发出来,供大家参考.这个是自己做的,仿优酷客户端的. 先看效果: ****************** ...

  2. 仿优酷Android客户端图片左右滑动(自动滑动)

    最终效果: 页面布局main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayou ...

  3. JavaScript使用DeviceOne开发实战(四)仿优酷视频应用

    开发之前需要考虑系统的差异性,比如ios手机没有回退键,所以在开发时一定要考虑二级界面需要有回退键,否则ios的手机就会陷入到这个页面出不去了.安卓系统有回退键,针对这个情况需要要求用户在3秒钟之内连 ...

  4. 高仿优酷Android客户端图片左右滑动(自动切换)

    本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能 ...

  5. CSIC_716_20191224【python基础结课作业--仿优酷练习】

    需 求:********管理员界面******** 1 注册 2 登录 3 上传视频 4 删除视频 5 发布公告 ********普通用户界面******** 1 注册 2 登录 3 冲会员 4 查看 ...

  6. android之官方导航栏ActionBar(三)之高仿优酷首页

    一.问题概述 通过上两篇文章,我们对如何使用ActionBar大致都已经有了认识.在实际应用中,我们更多的是定制ActionBar,那么就需要我们重写或者定义一些样式来修饰ActionBar,来满足具 ...

  7. 优酷项目之 ORM(数据库对象关系映射)代码重写

    前言: 我们在操作数据库时候一般都是通过sql代码来操作mysql数据库中相关数据,这就需要懂得sql语句,那么怎么样才能在不懂sql语句的情况下通过我们所学的python代码来实现对mysql数据库 ...

  8. mysql数据库实战之优酷项目

    管理员: 1.注册功能 客户端 1-1.选择每个功能之前都需要都需要需要连接上服务器,即需要一个socket对象,每个函数传一个client 1-2.密码在传递过程中不能是明文吧,需要加密,可选择ha ...

  9. Android Viewpager实现图片轮播(仿优酷效果)

    1 http://blog.csdn.net/t12x3456/article/details/8160128 2 http://www.cnblogs.com/androidez/archive/2 ...

随机推荐

  1. AcWing:109. 天才ACM(倍增 + 归并排序)

    给定一个整数 MM,对于任意一个整数集合 SS,定义“校验值”如下: 从集合 SS 中取出 MM 对数(即 2∗M2∗M 个数,不能重复使用集合中的数,如果 SS 中的整数不够 MM 对,则取到不能取 ...

  2. vue+ts搭建项目

    Tip: 为了避免浪费您的时间,本文符合满足以下条件的同学借鉴参考 1.本文模版不适用于小型项目,两三个页面的也没必要用vue2.对typescript.vue全家桶能够掌握和运用 此次项目模版主要涉 ...

  3. 2018-2019-2 20165215《网络对抗技术》Exp8 Web基础

    目录 实验内容 基础问题回答 实验步骤 (一)Web前端HTML (二) Web前端javascipt (三)Web后端:MySQL基础:正常安装.启动MySQL,建库.创建用户.修改密码.建表 (四 ...

  4. linu逻辑分区动态调整大小

    注意: 这个动态调整的方法是有丢数据风险的,要确保调整的源分区没有使用或者使用率很低.源分区中如果有重要的文件最好先备份 在centos 6.5上操作过 lvdisplay 查看已有的分区的大小 lv ...

  5. js如何获取鼠标位置

    获取鼠标位置,首先需要加载js文件: 然后设置一个div,给定大小: 最后进行具体操作: //首先要先设置一个div,给定大小 <div id="m"></div ...

  6. 在Excel中,已知身份证号码,如何批量计算其实际年龄?

    昨天,上司问我:..,你会在Excel中计算年龄吗?当时,一下促住了.说真的,还真不会.今天研究了一下,写下来,方便日后查看. 首先,得有一张已知姓名和相应身份证号的原表吧. 在这张表上再加上三列:出 ...

  7. JDBC插入数据,获取自增长值

    package com.loaderman.demo.c_auto; public class Dept { private int id; private String deptName; publ ...

  8. [Python]在python中调用shell脚本,并传入参数-02python操作shell实例

    首先创建2个shell脚本文件,测试用. test_shell_no_para.sh 运行时,不需要传递参数 test_shell_2_para.sh 运行时,需要传递2个参数  test_shell ...

  9. Windows安装使用npm(Nodejs)

    转载参考:https://blog.csdn.net/han0373/article/details/80606487 1:下载 https://nodejs.org/en/ 2:查看是否安装成功 w ...

  10. fiddler抓取https的请求详解

    本文主要说明了自己在设置fiddler抓取https过程中所遇到的问题及解决步骤,特别是fiddler在设置证书的环节遇到的各种奇葩问题,特此分享! 声明:本文为原创文章,转载请注明来源:https: ...