culture

2023/05/09 10-minute read

中华文化

起源

很早就在Github上看见了https://github.com/chinese-poetry/chinese-poetry这个仓库,当时觉得真的太棒了,那时候的我还不了解ORM, 只是知道有这么个东西,关于ORM的中文解释读了很多遍,懂了但也只是知道而已,并没有实际的体会。那时候的我还执着于mysql,对于sqlite不屑一顾。

那时候看到这么好的诗词文化库,第一个念头就是,要是能把它们存到本地数据库里面,那该多好啊,可以很方便查看,于是就开始吭哧吭哧搞了起来。

谁曾想,这一搞竟然搞了很长时间,并且还写了两个版本,因为第一版时间太久了,在操作数据库这部分,当时还去查找了各种优化方式,其中一种是不要单次提交, 而是一次性提交,再一个就是使用了多进程来加速,并且还配上了log来看大概需要多久,记得当初这个效率十分慢,跑一次大概要一个小时。代码会在最后给出。

mariadb 是我最喜欢的数据库,无他,只是因为它是开源免费的。由于对数据库的SQL语句并不是很熟悉,加上一直记得要注意SQL注入,于是查了些资料, 奈何最后写出来的代码还是一团糟,现在看起来,当初写的难免有些幼稚。

转折

处于对文化的热爱,很喜欢苏轼的词,但远山长,云山乱,晓山青,读来朗朗上口,相比于诗我更偏爱词。词里有李煜的梦中思故国,有辛弃疾的慷慨激昂, 有晏殊的娴雅情思,有李清照的怀乡悼亡,还有很多很多

也喜欢屈原的离骚,虽然时间上相隔了千余年,但力透古今的文字,就像是有一种魔力,跨越了千年的时空,直击到心底最深处,震颤了灵魂,注入血液之中, 翻涌流淌。

一晃过了很久,逛Github时候又发现了它,而此时的我已经了解sqlite,并且真正会运用ORM了,而这,令我大为震撼。

说来也是巧合,我在学习Flask的过程中,碰到了sqlalchemy,当时的是flask-sqlalchemy,认识到了modules的方式,正式这些巧合,让我突发联想, 于是便洋洋撒撒写下新的代码。彼时的我还没意识到,它能带给我多少惊喜。有了之前的经验,在写代码的时候先写了一个demo,然后便开始拆分成一个个模块, 使其进行组合,以便于复用。在拆分代码使其结构化的过程,加上对于sqlalchemy的理解,以及纯粹的目的,便有了现在的新代码。

sqlite也成为了我的选择,我放弃mariadb,不是因为它不好,也不是因为性能不如sqlite,只是因为sqlite方便,它是Python自带的。 很多时候,我们都没有做错什么,只是我们不合适罢了,如果一定要加上一个限定的话,我觉得是此时此刻不合适罢了。

生活就是这样,在什么都不懂得年纪,带着一腔热血,搞了半天,结果灰头土脸的宣布“胜利”而告终;当成长后,在有了曾经不曾有的实力后, 却丧失了当初的热忱和喜悦,关于从一小时四十五分钟到一小时三十分钟速度提升的兴奋感。

新的代码,仅仅花费一分钟就搞定了所有的事情,并且还把繁简转换给做了。速度提升了60倍,但是喜悦的感受不及当初十分之一,热爱依旧热爱, 只是少了当初那份激情,喜欢依旧喜欢,只是变得不再溢于言表,而是如品茶似的调剂生活。

尾章

我们正在失去,失去我们所失去的,失去,永久地失去

行香子·过七里濑
苏轼 〔宋代〕
一叶舟轻,双桨鸿惊。水天清、影湛波平。鱼翻藻鉴,鹭点烟汀。过沙溪急,霜溪冷,月溪明。
重重似画,曲曲如屏。算当年、虚老严陵。君臣一梦,今古空名。但远山长,云山乱,晓山青。

代码

第一版代码

import json
import logging
import os
import time

import mariadb

# config path
root_path = r'D:\chinese-poetry-master'
tangshi_path = os.path.join(root_path, r'json')
songci_path = os.path.join(root_path, r'ci')
huajian_path = os.path.join(root_path, r'wudai\huajianji')
shijing_path = os.path.join(root_path, r'shijing')

# config mariadb connect
pool = mariadb.ConnectionPool(
    pool_name='my_pool',
    pool_size=4,
    host='127.0.0.1',
    user='root',
    password='root',
    database='poem',
    autocommit=True,
)
# config log
t = time.localtime(time.time())
cur_time = f'{t.tm_year:04}{t.tm_mon:02}{t.tm_mday:02}'
logging.basicConfig(format="%(asctime)s %(levelname)s [line:%(lineno)d] %(message)s",
                    datefmt="%Y-%m-%d %H:%M:%S(%p)",
                    level=logging.DEBUG,
                    handlers=[logging.FileHandler(filename=cur_time + ".log", encoding='utf-8', mode='a+')])


def get_paths(path) -> list:
    file_paths = []
    files = os.listdir(path)
    for file in files:
        if '.json' in file:
            file_paths.append(os.path.join(path, file))
    if not file_paths:
        logging.info(f"json file is None: {path}")
    return file_paths


def save_to_mariadb(file_path, mtype=None):
    with open(file_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    flag = True
    if mtype == 'songci':
        for i in data:
            m_rhythmic, m_author, m_paragraphs = i["rhythmic"], i["author"], ''.join(i["paragraphs"])
            cursor.execute("select * from ci where rhythmic = ? and author = ? and  paragraphs = ?",
                           (m_rhythmic, m_author, m_paragraphs))
            if cursor.rowcount == 0:
                cursor.execute("INSERT INTO ci (rhythmic,author,paragraphs) VALUES (?, ?, ?)",
                               (m_rhythmic, m_author, m_paragraphs))
            elif cursor.rowcount != 1:
                if flag:
                    logging.info(f"Duplicate records exist in the database. file path is {file_path}")
                    flag = False
                [logging.info(i) for i in cursor]
        ...
    elif mtype == 'author_ci' or mtype == 'author_shi':
        for i in data:
            if mtype == 'author_ci':
                m_description, m_name, m_short_description = i["description"], i["name"], i["short_description"]
                cursor.execute("select * from author where full_desc = ? and author = ? and  short_desc = ?",
                               (m_description, m_name, m_short_description))
                if cursor.rowcount == 0:
                    cursor.execute("INSERT INTO author (author,full_desc,short_desc) VALUES (?, ?, ?)",
                                   (m_name, m_description, m_short_description))
                elif cursor.rowcount != 1:
                    if flag:
                        logging.info(f"Duplicate records exist in the database.file path is {file_path}")
                        flag = False
                    [logging.info(i) for i in cursor]
            elif mtype == 'author_shi':
                m_desc, m_name, m_id = i["desc"], i["name"], i["id"]
                cursor.execute("select * from author where full_desc = ? and author = ? and  id = ?",
                               (m_desc, m_name, m_id))
                if cursor.rowcount == 0:
                    cursor.execute("INSERT INTO author (author,full_desc,self_id) VALUES (?, ?, ?)",
                                   (m_name, m_desc, m_id))
                elif cursor.rowcount != 1:
                    if flag:
                        logging.info(f"Duplicate records exist in the database.file path is {file_path}")
                        flag = False
                    [logging.info(i) for i in cursor]
    elif mtype == 'tangshi':
        for i in data:
            m_author, m_paragraphs, m_title, m_id = i["author"], ''.join(i["paragraphs"]), i["title"], i["id"]
            cursor.execute("select * from shi where author = ? and paragraphs = ? and  title = ? and self_id = ?",
                           (m_author, m_paragraphs, m_title, m_id))
            if cursor.rowcount == 0:
                cursor.execute("INSERT INTO shi (author,paragraphs,title,self_id) VALUES (?, ?, ?,?)",
                               (m_author, m_paragraphs, m_title, m_id))
            elif cursor.rowcount != 1:
                if flag:
                    logging.info(f"Duplicate records exist in the database. file path is {file_path}")
                    flag = False
                [logging.info(i) for i in cursor]
    else:
        logging.debug("type out of range")


def json_file(file_paths: list):
    for path in file_paths:
        logging.debug(f"Start processing file:{path}")
        if os.path.split(path)[0] == tangshi_path:
            if "author" in os.path.basename(path):
                save_to_mariadb(path, 'author_shi')
                ...
            elif "poet" in os.path.basename(path):
                save_to_mariadb(path, 'tangshi')
                ...
        elif os.path.split(path)[0] == songci_path:
            if os.path.basename(path) == "author.song.json":
                save_to_mariadb(path, 'author_ci')
            elif "ci.song" in os.path.basename(path):
                save_to_mariadb(path, 'songci')
            else:
                logging.debug(f"the file: {os.path.basename(path)} out of program")
                ...
        else:
            logging.warning("Exceeds the processing scope of the program. Check whether the problem exists.")


def create_table(create=True) -> None:
    """
    include create and drop
    :param create: if you need drop table, make create false, be careful!!!
    :return:None
    """
    table_names = ['shi', 'ci', 'author']
    commands = []
    create_shi = """
        create table if not exists shi(
        id int not null auto_increment,
        author varchar(255),
        paragraphs text,
        title varchar(255), 
        self_id varchar(255),
        dynastic varchar(255),
        primary key (id)
    ); 
    """
    create_ci = """
        create table if not exists ci(
            id int not null auto_increment,
            author varchar(255),
            paragraphs text,
            rhythmic varchar(255), 
            primary key (id)
        ); 
        """
    create_author = """
        create table if not exists author(
            id int not null auto_increment,
            author varchar(255),
            full_desc text,
            short_desc text,
            self_id varchar(255),
            dynastic varchar(255),
            primary key (id)
        ); 
    """
    commands.append(create_shi)
    commands.append(create_ci)
    commands.append(create_author)
    for i in commands:
        try:
            cursor.execute(i)
        except mariadb.Error as e:
            logging.error(f"Error create table {i}: {e}")
    ...
    if not create:
        for i in table_names:
            command = "drop table " + i
            try:
                cursor.execute(command)
                logging.warning(command)
            except mariadb.Error as e:
                logging.error(f"Error drop table {i}: {e}")


def core_exec():
    json_file(get_paths(tangshi_path))
    json_file(get_paths(songci_path))
    ...


if __name__ == '__main__':
    conn = pool.get_connection()
    cursor = conn.cursor()
    create_table()
    core_exec()
    cursor.close()
    conn.close()
    ...

第二版代码

import json
import logging
import multiprocessing
import os
import sys
import time
from multiprocessing import Manager

import mariadb
import opencc

# global config
isDirectInsert = True  # check the value if exists, before insert,Recommend True.
isSimplifiedChinese = True  # origin data is Traditional Chinese,Recommend True.
isDropTable = False  # if true,table will be dropped,include data of table,Recommend False
INSERT_NUMBER = 500  # Recommend 500
isMultiProcess = True
shi_path = r"D:\chinese-poetry-master\json"
ci_path = r"D:\chinese-poetry-master\ci"

# config mariadb connect
pool = mariadb.ConnectionPool(
    pool_name='pools',
    pool_size=4,
    host='127.0.0.1',
    user='root',
    password='root',
    database='test2',
)

# config log encoding 参数需要 python3.9及以上版本,配置目的为了防止logging中文乱码
LOG_FORMAT = "%(asctime)s %(levelname)s [line:%(lineno)d] %(message)s"
LOG_DATE_FORMATE = "%Y-%m-%d %H:%M:%S(%p)"
LOG_FILENAME = "poem.log"
logging.basicConfig(format=LOG_FORMAT, datefmt=LOG_DATE_FORMATE, level=logging.DEBUG, filename=LOG_FILENAME,
                    encoding="utf-8")


class Table(object):
    def __init__(self, table_name: str, primary_key: str, column_name: list, column_desc: list,
                 column_info: dict = None):
        self.table_name = table_name
        self.primary_key = primary_key
        self.column_name = column_name
        self.column_desc = column_desc
        if column_info:
            self.column_info = column_info
        else:
            self.column_info = dict(zip(column_name, column_desc))

    def show(self):
        sql_str = ""
        for key, value in self.column_info.items():
            sql_str = sql_str + key + " " + value + ","
        table = f"""
            create table if not exists {self.table_name}(
                {sql_str}
                primary key ({self.primary_key})
            );
        """
        print(table)


def timeit(func):
    def timeit_wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        total_time = end_time - start_time
        # logging.debug(f'Function {func.__name__} args:{args} kwargs:{kwargs} Took {total_time:.4f} seconds')
        logging.debug(f'Function {func.__name__} Took {int(total_time) // 3600} hours '
                      f'{int(total_time // 60)} minutes {int(total_time % 60)} seconds')
        return result

    return timeit_wrapper


def create_table(table_name: str, primary_key: str, column_name: list, column_desc: list):
    column_info = dict(zip(column_name, column_desc))
    sql_str = ""
    for key, value in column_info.items():
        sql_str = sql_str + key + " " + value + ","
    create = f"""
        create table if not exists {table_name}(
            {sql_str}
            primary key ({primary_key})
        );
    """
    logging.debug(f"create info {create}")
    return create


def drop_table(table_name):
    drop = "drop table " + table_name
    return drop


def t2s(data):
    """
    Traditional to Simplified.
    Data type can be list, str, tuple.
    input data == return data
    """
    cc = opencc.OpenCC("t2s.json")
    if isinstance(data, list):
        result = []
        for i in data:
            result.append(cc.convert(i))
        return result
    elif isinstance(data, str):
        result = cc.convert(data)
        return result
    elif isinstance(data, tuple):
        result = []
        for i in data:
            result.append(cc.convert(i))
        result = tuple(result)
        return result
    else:
        logging.debug("args type out of range!!!")


def get_json_paths(root_path) -> list:
    """
    获取指定路径下符合条件的文件的绝对路径
    :param root_path:
    :return:
    """
    dirs = os.listdir(root_path)
    filter_paths = []
    for file in dirs:
        if '0' in file and 'json' in file:  # 唐诗&宋词
            filter_paths.append(os.path.join(root_path, file))
    if not filter_paths:
        logging.warning(f"No file that meets the rule exists in the directory :{root_path}")
    logging.debug(f"after filter path is {filter_paths}")
    return filter_paths


def get_json_data(json_path):
    with open(json_path, 'r', encoding='utf-8') as f:
        data = json.load(f)
    return data


def set_table(table_name):
    table_name = table_name
    if table_name == 'shi':
        primary_key = 'id'
        column_name = ["id", "title", "author", "dynastic", "content", "self_id", "simple"]
        column_desc = ["int not null auto_increment", "varchar(255)", "varchar(255)", "varchar(255)", "text",
                       "varchar(255)", "varchar(255)"]
    elif table_name == 'ci':
        primary_key = 'id'
        column_name = ["id", "title", "author", "dynastic", "content"]
        column_desc = ["int not null auto_increment", "varchar(255)", "varchar(255)", "varchar(255)", "text"]
        ...
    else:
        sys.exit()
    tb = Table(table_name, primary_key, column_name, column_desc)
    return tb


def save_to_mariadb(tb: Table, paths: list):
    conn = pool.get_connection()
    cursor = conn.cursor()
    if isDropTable:
        cursor.execute(drop_table(tb.table_name))
    cursor.execute(create_table(tb.table_name, tb.primary_key, tb.column_name, tb.column_desc))
    for file_path in paths:
        logging.info(f"Processing file:{file_path}")
        data = get_json_data(file_path)
        mult_data = []
        for index, value in enumerate(data):
            if tb.table_name == "shi":
                column_names = (tb.column_name[1], tb.column_name[2], tb.column_name[4], tb.column_name[5])
                column_value = (value["title"], value["author"], ''.join(value["paragraphs"]), value["id"])
            elif tb.table_name == "ci":
                column_names = (tb.column_name[1], tb.column_name[2], tb.column_name[4])
                column_value = (value["rhythmic"], value["author"], ''.join(value["paragraphs"]))
            else:
                sys.exit()
            if isSimplifiedChinese:
                column_value = t2s(column_value)

            column_fills = f"({(len(column_names) - 1) * '?,' + '?'})"
            column_str = ''
            for i, j in enumerate(column_names):
                if i == len(column_names) - 1:
                    column_str = column_str + j
                else:
                    column_str = column_str + j + ","
            column_str = "(" + column_str + ")"
            if INSERT_NUMBER > 1:
                mult_data.append(column_value)
                if (len(mult_data) == INSERT_NUMBER) or (index == (len(data) - 1)):
                    cursor_new = conn.cursor()
                    cursor_new.executemany(f"insert into {tb.table_name} {column_str} values {column_fills}", mult_data)
                    cursor_new.close()
                    mult_data = []
            else:
                cursor.execute(f"insert into {tb.table_name} {column_str} values {column_fills}", column_value)
                logging.debug(f"""sql command is "insert into {tb.table_name} {column_str} values {column_fills}" """)

    conn.commit()
    conn.close()


def error(value):
    print(f'error:{value}')


def core_exec():
    if isMultiProcess:
        logging.info("now multiprocess:")
        multi_core = multiprocessing.Pool(processes=3)
        multi_core.apply_async(save_to_mariadb, args=(set_table("ci"), get_json_paths(ci_path)), error_callback=error)
        multi_core.apply_async(save_to_mariadb, args=(set_table("shi"), get_json_paths(shi_path)), error_callback=error)
        multi_core.close()
        multi_core.join()
    else:
        save_to_mariadb(set_table("ci"), get_json_paths(ci_path))
        save_to_mariadb(set_table("shi"), get_json_paths(shi_path))


def log_init():
    logging.info("Program start...")
    logging.info(f"params:\nisDirectInsert is:{isDirectInsert};isSimplifiedChinese is:{isSimplifiedChinese}\n"
                 f"isDropTable is:{isDropTable};INSERT_NUMBER is:{INSERT_NUMBER}\n"
                 f"shi_path is:{shi_path};ci_path is{ci_path}")


if __name__ == '__main__':
    log_init()
    core_exec()

新代码 sqlalchemy with sqlite

import json
import os
import time
from os.path import join

import opencc
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session

from modules import Base, YuanQu, HuaJianJi, ChuCi, ShiJing, LunYu, SiShuWuJing, SongCi, TangShi, TangShi_Simple


def create_table(is_force=False):
    if is_force:
        Base.metadata.drop_all(engine)
        Base.metadata.create_all(engine)
    else:
        Base.metadata.create_all(engine,checkfirst=True)
    

class JsonData(object):
    def __init__(self,path,besides=[]):
        self.path = path
        self.besides = besides
    def get_files(self):
        files = os.listdir(self.path)
        files_new = [os.path.join(self.path, _) for _ in files if _.endswith(".json")]
        return files_new
    @staticmethod
    def filter_files(files, besides: list = [], regex: str = None):
        def check_file(file):
            is_in = False
            for check in besides:
                if check in file:
                    is_in = True
                    break
            return is_in
        result = []
        for json_file in files:
            # 排除文件路径干扰,只取文件名检测
            json_file_name = os.path.basename(json_file)
            ret = check_file(json_file_name)
            if not ret:
                result.append(json_file)
        if regex:
            ...
        return result
    @staticmethod
    def get_data(path):
        with open(path, 'r', encoding="utf-8") as f:
            json_data = json.load(f)
        return json_data
    def get_all_data(self):
        files = self.get_files()
        files_new = self.filter_files(files,besides=self.besides)
        _temp = []
        for file in files_new:
            json_data = self.get_data(file)
            for d in json_data:
                _temp.append(d)
        return _temp
    def run(self):
        return self.get_all_data()


def yuanqu(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        dynasty = data.get("dynasty", "None")
        author = data.get("author", "None")
        paragraphs = data.get("paragraphs", "None")
        paragraphs = "".join(paragraphs)
        title = data.get("title", "None")
        _session.add(YuanQu(dynasty=dynasty, author=author, paragraphs=paragraphs, title=title))

def huajian(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        title = data.get("title", "None")
        paragraphs = data.get("paragraphs", "None")
        paragraphs = "".join(paragraphs)
        author = data.get("author", "None")
        rhythmic = data.get("rhythmic","None")
        notes = data.get("notes","None")
        notes = "".join(notes)
        _session.add(HuaJianJi(rhythmic=rhythmic, author=author, paragraphs=paragraphs, title=title, notes=notes))


def quantangshi(path,besides,_session:Session,is_simplified=False):
    datas = JsonData(path, besides=besides).run()
    converter = opencc.OpenCC('t2s')
    for data in datas:
        author = data.get("author", "None")
        paragraphs = data.get("paragraphs", "None")
        paragraphs = "".join(paragraphs)
        note = data.get("note","None")
        note = "".join(note)
        title = data.get("title", "None")
        _session.add(TangShi(author=author, paragraphs=paragraphs,note=note,title=title))
        if is_simplified:
            _session.add(TangShi_Simple(author=converter.convert(author), paragraphs=converter.convert(paragraphs),
                                        note=converter.convert(note), title=converter.convert(title)))

def sishuwujing(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        if not isinstance(data,dict):
            continue
        chapter = data.get("chapter", "None")
        paragraphs = data.get("paragraphs", "None")
        paragraphs = "".join(paragraphs)
        _session.add(SiShuWuJing(chapter=chapter, paragraphs=paragraphs))
    pass


def songci(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        author = data.get("author", "None")
        paragraphs = data.get("paragraphs", "None")
        paragraphs = "".join(paragraphs)
        rhythmic = data.get("rhythmic","None")
        _session.add(SongCi(author=author, paragraphs=paragraphs, rhythmic=rhythmic))
    pass


def chuci(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        section = data.get("section", "None")
        author = data.get("author", "None")
        title = data.get("title", "None")
        content = data.get("content","None")
        content = "".join(content)
        _session.add(ChuCi(section=section, author=author, content=content, title=title))


def lunyu(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        chapter = data.get("chapter","None")
        paragraphs = data.get("paragraphs", "None")
        paragraphs = "".join(paragraphs)
        _session.add(LunYu(chapter=chapter, paragraphs=paragraphs))
    pass


def shijing(path,besides,_session:Session):
    datas = JsonData(path,besides=besides).run()
    for data in datas:
        section = data.get("section", "None")
        title = data.get("title", "None")
        chapter = data.get("chapter","None")
        content = data.get("content","None")
        content = "".join(content)
        _session.add(ShiJing(section=section, chapter=chapter, content=content, title=title))


def core(_session:Session):
    current_dir = os.path.dirname(__file__)
    basedir = os.path.dirname(current_dir)
    
    yuanqu_dir = join(basedir,f"元曲")
    hujian_dir = join(basedir,f"五代诗词{os.sep}huajianji")
    chuci_dir = join(basedir,f"楚辞")
    shijing_dir = join(basedir,f"诗经")
    lunyu_dir = join(basedir,f"论语")
    sishuwujing_dir = join(basedir,f"四书五经")
    songci_dir = join(basedir,f"宋词")
    quantangshi_dir = join(basedir,f"全唐诗")
    
    yuanqu(_session = _session,path=yuanqu_dir, besides=[])
    huajian(_session=_session,path=hujian_dir,besides=['huajianji-0-preface.json'])
    sishuwujing(_session = _session,path=sishuwujing_dir, besides=[])
    chuci(_session = _session,path=chuci_dir, besides=[])
    lunyu(_session = _session,path=lunyu_dir, besides=[])
    shijing(_session = _session,path=shijing_dir, besides=[])
    songci(_session=_session, path=songci_dir, besides=["author.song.json"])
    quantangshi(_session=_session, path=quantangshi_dir, besides=["authors", "唐诗", "表面结构字"],is_simplified=True)
    
    
if __name__ == '__main__':
    s = time.time()
    url = f"""sqlite:///{os.path.join(os.path.dirname(__file__), "culture.db")}"""
    engine = create_engine(url)
    Session = sessionmaker(engine)
    session = Session()
    create_table(is_force=True)
    core(_session=session)
    session.commit()
    session.close()
    e = time.time()
    print(f"spend time {int(e-s)} seconds")
from sqlalchemy import Column, Integer, Text
from sqlalchemy import String
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class YuanQu(Base):
    __tablename__ = "YuanQu"
    id = Column(Integer, primary_key=True)
    dynasty = Column(String(10))
    author = Column(String(20))
    paragraphs = Column(Text)
    title = Column(String(100))
    
class HuaJianJi(Base):
    __tablename__ = "HuaJianJi"
    id = Column(Integer, primary_key=True)
    title = Column(String(100))
    paragraphs = Column(Text)
    author = Column(String(20))
    rhythmic = Column(String(20))
    notes = Column(Text)

class ChuCi(Base):
    __tablename__ = "ChuCi"
    id = Column(Integer, primary_key=True)
    title = Column(String(100))
    section = Column(String(20))
    author = Column(String(20))
    content = Column(Text)

class ShiJing(Base):
    __tablename__ = "Shijing"
    id = Column(Integer, primary_key=True)
    title = Column(String(100))
    chapter = Column(String(20))
    section = Column(String(20))
    content = Column(Text)
    
class LunYu(Base):
    __tablename__ = "LunYu"
    id = Column(Integer, primary_key=True)
    chapter = Column(String(20))
    paragraphs = Column(Text)
class SiShuWuJing(Base):
    __tablename__ = "SiShuWuJing"
    id = Column(Integer, primary_key=True)
    chapter = Column(String(20))
    paragraphs = Column(Text)

class SongCi(Base):
    __tablename__ = "SongCi"
    id = Column(Integer, primary_key=True)
    author = Column(String(20))
    paragraphs = Column(Text)
    rhythmic = Column(String(100))

class TangShi(Base):
    __tablename__ = "TangShi"
    id = Column(Integer, primary_key=True)
    author = Column(String(20))
    paragraphs = Column(Text)
    note = Column(Text)
    title = Column(String(100))
    
class TangShi_Simple(Base):
    __tablename__ = "TangShi_Simple"
    id = Column(Integer, primary_key=True)
    author = Column(String(20))
    paragraphs = Column(Text)
    note = Column(Text)
    title = Column(String(100))