仿优酷1

一、需求分析

1.管理员:

注册、登录、上传视频、删除视频、发布公告

2.用户:

注册、登录、充会员、查看视频、下载免费视频、下载收费视频、查看下载记录、查看公告

二、程序的架构设计(三层架构)

1.用户视图层

与用户交互

2.接口层

处理核心业务逻辑

3.数据层

对数据进行存取

三、ORM(对象关系映射)

将对象映射成数据表中的一条条记录

类 ----> 表名

对象 ----> 记录

对象.属性 ----> 字段

# 问题1: 每一张表类,都必须定义一个__init__方法,
# 假设有100张表,就得写100次,无法确定每张表的字段个数,以及字段的名字;
# 解决1: 通过继承字典类,解决该问题;

# 问题2: 继承的字典无法通过 对象.属性的 取值方式, 对象.属性 = 属性值 增加或修改属性的操作?
# 解决2: __getattr__解决了取值方式, __setattr__解决了增加或修改属性的方式

class Models(dict, metaclass=OrmMetaClass):

    # 对象.属性, 属性没有时触发
    def __getattr__(self, item):
        # print(self)
        return self.get(item)  # {'name': 'tank', 'pwd': '123'}.get('name') ----> tank

    # 对象.属性 = 属性值 时触发
    def __setattr__(self, key, value):
        # print(key, value)
        # print(self)  # {'name': 'tank', 'pwd': '123'}
        # 给字典添加键值对的方式
        self[key] = value
# 问题3: 一张表中只能有一个唯一的主键,在当前表类中,无法控制用户定义类的型?
# 自定义元类:
# 解决三件事情 ---》
# 1、保证一张表必须要有表名  2、保证一张表中只能有一个主键
# 3、将所有 “字段名” 与 “字段对象” 添加到一个独立的字典中(mappings),
# 以key(字段名):value(字段对象) , 添加到类的名称空间中,方便后期使用


class OrmMetaClass(type):

    # __call__ ---> __new__ ----> type.__new__() ---> obj ---> Models
    # 只要定义类就会触发__new__, 因为类也是对象,OrmMetaClass() ---> Models类对象 、User类对象
    def __new__(cls, class_name, class_bases, class_attr):
        # class_name, class_bases, class_attr = args
        # print(f'类名: {class_name}')
        # print(f'基类: {class_bases}')
        # print(f'类的名称空间: {class_attr}')

        # 1、过滤Models类
        if class_name == 'Models':
            # 将models类的类名、基类、名称空间原路返回
            return type.__new__(cls, class_name, class_bases, class_attr)

        # 2、获取 table 表名,若自定义则获取,没有则默认使用类名
        # dict.get(key) ---> key若有则返回对应的值,若没有则返回默认值 class_name就是默认值
        # 将类名当做表名
        table_name = class_attr.get('table_name', class_name)

        # print(table_name)

        # 打印修改类名称空间前的  名称空间
        # print(class_attr)

        # 主键值: 主键名为 字段名, 比如 主键是 id字段 ---》 id就是主键的名字
        primary_key = None

        # 存放字段名与字段对象的字典
        mappings = {}

        # 3、保证一张表只能有一个唯一的主键
        # 循环遍历类的名称空间
        for k, v in class_attr.items():
            # print(k, v)
            # 将字段以外的属性过滤掉
            # 判断当前的v是否是字段对象
            if isinstance(v, Field):
                # print(k, v)
                # print(v.__dict__)
                # 4、将所有 “字段名” 与 “字段对象” 添加到一个独立的字典中(mappings)
                mappings[k] = v

                # 判断字段对象如果有 主键primary_key, 则为primary_key 变量赋值
                if v.primary_key:
                    # 若第二次进来,primary有值,证明有主键,抛出异常
                    if primary_key:
                        raise TypeError('一张表只能有一个主键')

                    # primary_key = k
                    # print(k == v.name, 111111)
                    # 给primary_key变量做一个赋值操作
                    primary_key = v.name

        # 5、过滤掉类名称空间中重复的字段属性
        for key in mappings.keys():
            class_attr.pop(key)


        if not primary_key:
            raise TypeError('必须要有一个主键!!!')

        # 6、给类的名称空间,添加table_name, primary_key,mappings属性;
        class_attr['table_name'] = table_name
        class_attr['primary_key'] = primary_key
        class_attr['mappings'] = mappings

        # print('*' * 100)
        # print(class_attr)

        return type.__new__(cls, class_name, class_bases, class_attr)
# 定义字段类型: 每个字段都应该有---> 字段名、字段类型、是否为主键、默认值
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


# varchar
class StringField(Field):
    def __init__(self, name,
                 column_type='varchar(64)',
                 primary_key=False, default=None):
        super().__init__(name, column_type, primary_key, 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)

ORM需要处理的事情:

1.控制表类的创建  ---> 控制表创建的过程

2.给表类封装 增、查、改 方法

四、封装mysql方法类

import pymysql


# MySQL连接类
class MySQL:

    __instance = None

    # 单例模式
    @classmethod
    def singleton(cls):
        if not cls.__instance:
            cls.__instance = cls()

        return cls.__instance

    # 实例化MySQL类时,获取数据库链接对象,获取游标对象
    def __init__(self):
        self.mysql_client = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123456',
            charset='utf8',
            database='orm_demo',
            autocommit=True
        )

        self.cursor = self.mysql_client.cursor(
            pymysql.cursors.DictCursor
        )

    # 自定义查询方法
    def select(self, sql, args=None):
        # 1、先提交查询sql语句
        # select * from table;
        # select * from table where id=%s;
        self.cursor.execute(sql, args)

        # 2、获取返回的查询结果
        # res ---> [{}, {}]
        res = self.cursor.fetchall()
        return res

    # 自定义提交sql语句方法,比如: insert、update
    def execute(self, sql, args):
        # 1、提交sql语句
        # insert into table(字段) values(%s);
        try:
            self.cursor.execute(sql, args)

        except Exception as e:
            print(e)

    def close(self):
        # 先关闭游标
        self.cursor.close()
        # 再关闭数据库连接
        self.mysql_client.close()
posted @ 2019-12-18 19:40  treeter  阅读(229)  评论(0编辑  收藏  举报