在开始编写ORM模块之前,我们需要先对db_helper进行重构,因为ORM最终生成的sql是需要转给db_helper来执行的,所以拥有一个功能完善、健壮的数据库操作类是非常必要的。

  这是项目原db_helper.py代码

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import psycopg2
  5. from common import log_helper
  6. from config import const
  7.  
  8. # 初始化数据库参数
  9. db_name = const.DB_NAME
  10. db_host = const.DB_HOST
  11. db_port = const.DB_PORT
  12. db_user = const.DB_USER
  13. db_pass = const.DB_PASS
  14.  
  15. def read(sql):
  16. """
  17. 连接pg数据库并进行数据查询
  18. 如果连接失败,会把错误写入日志中,并返回false,如果sql执行失败,也会把错误写入日志中,并返回false
  19. 如果所有执行正常,则返回查询到的数据,这个数据是经过转换的,转成字典格式,方便模板调用,其中字典的key是数据表里的字段名
  20. """
  21. try:
  22. # 连接数据库
  23. conn = psycopg2.connect(database=db_name, user=db_user, password=db_pass, host=db_host, port=db_port)
  24. # 获取游标
  25. cursor = conn.cursor()
  26. except Exception as e:
  27. print(e.args)
  28. log_helper.error('连接数据库失败:' + str(e.args))
  29. return False
  30. try:
  31. # 执行查询操作
  32. cursor.execute(sql)
  33. # 将返回的结果转换成字典格式
  34. data = [dict((cursor.description[i][0], value) for i, value in enumerate(row)) for row in cursor.fetchall()]
  35. except Exception as e:
  36. print(e.args)
  37. log_helper.error('sql执行失败:' + str(e.args) + ' sql:' + str(sql))
  38. return False
  39. finally:
  40. # 关闭游标和数据库链接
  41. cursor.close()
  42. conn.close()
  43. # 返回结果(字典格式)
  44. return data
  45.  
  46. def write(sql, vars):
  47. """
  48. 连接pg数据库并进行写的操作
  49. 如果连接失败,会把错误写入日志中,并返回false,如果sql执行失败,也会把错误写入日志中,并返回false,如果所有执行正常,则返回true
  50. """
  51. try:
  52. # 连接数据库
  53. conn = psycopg2.connect(database=db_name, user=db_user, password=db_pass, host=db_host, port=db_port)
  54. # 获取游标
  55. cursor = conn.cursor()
  56. except Exception as e:
  57. print(e.args)
  58. log_helper.error('连接数据库失败:' + str(e.args))
  59. return False
  60. try:
  61. # 执行sql语句
  62. cursor.execute(sql, vars)
  63. # 提交事务
  64. conn.commit()
  65. except Exception as e:
  66. print(e.args)
  67. # 如果出错,则事务回滚
  68. conn.rollback()
  69. log_helper.error('sql执行失败:' + str(e.args) + ' sql:' + str(sql))
  70. return False
  71. else:
  72. # 获取数据
  73. try:
  74. data = [dict((cursor.description[i][0], value) for i, value in enumerate(row))
  75. for row in cursor.fetchall()]
  76. except Exception as e:
  77. # 没有设置returning或执行修改或删除语句时,记录不存在
  78. data = None
  79. finally:
  80. # 关闭游标和数据库链接
  81. cursor.close()
  82. conn.close()
  83.  
  84. # 如果写入数据后,将数据库返回的数据返回给调用者
  85. return data

  通过对代码的简单分析,可以看到整个模块在初化时,载入数据库链接配置,对数据库的操作也只有简单读与写操作。这样的功能对于一般的数据库增删改查操作已经足够了,但如果业务复杂,有多个库、需要用到事务或者需要访问不同类型数据库时,它就不够用了。所以首先要做的就是对它进行重构,功能进行完善。

  首先我们需要将配置独立出来,当有需要链接多个数据库时,可以读取不同的配置文件,让程序更加方便灵活。

  在config目录下创建db_config.py文件(有多个库时,可以配置多个不同的参数来引用)

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. ### 数据库链接参数 ###
  5. DB = {
  6. 'db_host': '127.0.0.1',
  7. 'db_port': 5432,
  8. 'db_name': 'simple_db',
  9. 'db_user': 'postgres',
  10. 'db_pass': ''
  11. }
  12. # 是否将所有要执行的Sql语句输出到日志里
  13. IS_OUTPUT_SQL = False

  在配置中,我们同样定义了数据库连接地址、端口、数据库名称、用户名与密码。

  另外,为了方便我们进行排错,检查sql的生成情况,添加了IS_OUTPUT_SQL是否输出执行的sql语句到日志中这一个开关项,设置为True时,所有被执行的sql语句都会被写到日志中,方便下载日志下来进行分析。

  对于数据库操作模块,我们需要封装成一个类,在有需要调用时,就可以通过with语句进行初始化操作,设置对应的数据库链接配置,灵活的连接不同的数据库。

  在设计操作类时,我们需要思考几个问题:

  1.它可以支持多数据库操作,即读取不同的配置能连接操作不同的数据库(可以通过类初始化时进行注入配置信息)

  2.它需要支持with语句,当我们忘记关闭数据库游标和连接时,自动帮我们关闭(需要实现__enter__()与__exit__()方法)

  3.它需要支持数据库事务,当执行失败时,可以回滚数据,当所有sql执行都成功时,可以统一提交事务(需要创建rollback()与commit()方法)

  4.它需要支持查询、添加、修改、删除等操作,方便我们操作关系型数据库记录(需要创建sql执行方法)

  5.它需要支持sql执行优化,将超出指定执行时间的sql语句记录到日志中,方便开发人员进行分析(需要记录sql执行起始时间与结束时间,并进行计算,当这个时间大于指定值时执行日志写入程序)

  根据这些要求,我们初步设计出数据库操作类的基本模型

  1. class PgHelper(object):
  2. """postgresql数据库操作类"""
  3.  
  4. def __init__(self, db, is_output_sql):
  5. """初始化数据库操作类配置信息"""
  6.  
  7. def open_conn(self):
  8. """连接数据库,并建立游标"""
  9.  
  10. def close_conn(self):
  11. """关闭postgresql数据库链接"""
  12.  
  13. def __enter__(self):
  14. """初始化数据库链接"""
  15.  
  16. def __exit__(self, type, value, trace):
  17. """关闭postgresql数据库链接"""
  18.  
  19. def rollback(self):
  20. """回滚操作"""
  21.  
  22. def commit(self):
  23. """提交事务"""
  24.  
  25. def execute(self, query, vars=None):
  26. """执行sql语句查询,返回结果集或影响行数"""
  27.  
  28. def write_log(self, start_time, end_time, sql):
  29. """记录Sql执行超时日志"""

  接下来,我们来一一实现上面的各个方法

  首先是完成初始化方法,我们可以通过注入的方法,将db_config配置信息里的参数注入进来初始化。连接不同的数据库时,可以注入不同的配置信息。

  1. class PgHelper(object):
  2. """postgresql数据库操作类"""
  3.  
  4. def __init__(self, db, is_output_sql):
  5. self.connect = None
  6. self.cursor = None
  7. # 初始化数据库参数
  8. self.db_name = db.get('db_name')
  9. self.db_user = db.get('db_user')
  10. self.db_pass = db.get('db_pass')
  11. self.db_host = db.get('db_host')
  12. self.db_port = db.get('db_port')
  13. # 是否将所有要执行的Sql语句输出到日志里
  14. self.is_output_sql = is_output_sql

  然后我们来创建数据库打开连接方法与关闭连接的方法,当数据库连接失败时会抛出异常,程序会自动调用log_helper.error()方法,将异常写入日志当中,并第一时间发送邮件通知开发人员,方便开发人员即时排错。

  1. def open_conn(self):
  2. """连接数据库,并建立游标"""
  3. try:
  4. if not self.connect:
  5. self.connect = psycopg2.connect(database=self.db_name, user=self.db_user, password=self.db_pass, host=self.db_host, port=self.db_port)
  6. return self.connect
  7. except Exception as e:
  8. log_helper.error('连接数据库失败:' + str(e.args))
  9. return False
  10.  
  11. def close_conn(self):
  12. """关闭postgresql数据库链接"""
  13. # 关闭游标
  14. try:
  15. if self.cursor:
  16. self.cursor.close()
  17. except Exception:
  18. pass
  19. # 关闭数据库链接
  20. try:
  21. if self.connect:
  22. self.connect.close()
  23. except Exception:
  24. pass

  通过重写内置__enter__()与__exit__()方法,来实现with语句调用本类时,会自动对类进行初始化操作,自动创建数据库连接。当代码执行完毕后(程序退出with语句时),程序会自动调用对应的方法,将游标与数据库连接的关闭,避免手动操作时,忘记关闭连接出现异常。

  1. def __enter__(self):
  2. """初始化数据库链接"""
  3. self.open_conn()
  4. return self
  5.  
  6. def __exit__(self, type, value, trace):
  7. """关闭postgresql数据库链接"""
  8. self.close_conn()

  为了方便事务处理,增加回滚方法。用于事务中执行操作失败时,调用回滚方法执行回滚操作。

  1. def rollback(self):
  2. """回滚操作"""
  3. try:
  4. # 异常时,进行回滚操作
  5. if self.connect:
  6. self.connect.rollback()
  7. self.close_conn()
  8. except Exception as e:
  9. log_helper.error('回滚操作失败:' + str(e.args))

  还需要增加事务提交方法,方便sql执行增删改成功以后,提交事务更新数据。在开发中很多朋友经常会忘记执行提交事务操作,一直以为代码有问题没有执行成功。

  1. def commit(self):
  2. """提交事务"""
  3. try:
  4. if self.connect:
  5. self.connect.commit()
  6. self.close_conn()
  7. except Exception as e:
  8. log_helper.error('提交事务失败:' + str(e.args))

  为了方便查看sql语句转换效果,我们还可以增加获取sql语句生成方法,当然这个方法并没有太大的用途。

  1. def get_sql(self, query, vars=None):
  2. """获取编译后的sql语句"""
  3. # 记录程序执行开始时间
  4. start_time = time.clock()
  5. try:
  6. # 判断是否记录sql执行语句
  7. if self.is_output_sql:
  8. log_helper.info('sql:' + str(query))
  9. # 建立游标
  10. self.cursor = self.connect.cursor()
  11. # 执行SQL
  12. self.data = self.cursor.mogrify(query, vars)
  13. except Exception as e:
  14. # 将异常写入到日志中
  15. log_helper.error('sql生成失败:' + str(e.args) + ' query:' + str(query))
  16. self.data = '获取编译sql失败'
  17. finally:
  18. # 关闭游标
  19. self.cursor.close()
  20. # 记录程序执行结束时间
  21. end_time = time.clock()
  22. # 写入日志
  23. self.write_log(start_time, end_time, query)
  24.  
  25. return self.data

  因为,当你直接使用完整的sql语句执行时,并不需要这个方法。但是,你使用的是下面方式,执行后就会生成组合好的sql语句,帮助我们分析sql语句生成情况

  1. # 使用with方法,初始化数据库连接
  2. with db_helper.PgHelper(db_config.DB, db_config.IS_OUTPUT_SQL) as db:
  3. # 设置sql执行语句
  4. sql = """insert into product (name, code) values (%s, %s) returning id"""
  5. # 设置提交参数
  6. vars = ('zhangsan', '')
  7. # 生成sql语句,并打印到控制台
  8. print(db.get_sql(sql, vars))

  输出结果:

  1. b"insert into product (name, code) values ('zhangsan', '201807251234568') returning id"

  数据库最常见的操作就是增删改查操作,由于postgresql有个非常好用的特殊参数:returning,它可以在sql执行增改删结束后,返回我们想要的字段值,方便我们进行相应的判断与操作,所以增改删操作我们不需要将它与查询操作分离成两个方法,统一使用这个方法来获取数据库中返回的记录值。

  在实现这个方法之前,我们设计时要思考这几个问题:

  1.需要记录程序执行的起始与结束时间,计算sql语句执行时长,用来判断是否记录到日志中,方便开发人员进行分析优化sql语句

  2.需要根据参数判断,是否需要将所有执行的sql语句记录到日志中,方便开发人员有需要时,查看执行了哪些sql语句,进行数据与功能分析

  3.由于类在加载时就已经自动连接数据库了,所以在方法中不需要进行打开数据库链接操作

  5.在执行sql语句时,需要创建游标,然后执行sql语句

  6.为了让用户更好的体验,减少异常的直接抛出,需要进行异常捕捉,并将捕捉到的异常进行处理,记录到日志中方便开发人员分析错误,同时同步发送推送给相关人员,即时提醒错误

  7.sql执行成功以后,需要对返回的数据进行处理,组合成字典类型,方便前端使用

  8.完成数据处理后,需要及时关闭游标

  9.对返回的数据需要进行处理后,返回给上一级程序

  1. def execute(self, query, vars=None):
  2. """执行sql语句查询,返回结果集或影响行数"""
  3. if not query:
  4. return None
  5. # 记录程序执行开始时间
  6. start_time = time.clock()
  7. try:
  8. # 判断是否记录sql执行语句
  9. if self.is_output_sql:
  10. log_helper.info('sql:' + str(query))
  11. # 建立游标
  12. self.cursor = self.connect.cursor()
  13. # 执行SQL
  14. result = self.cursor.execute(query, vars)
  15. print(str(result))
  16. except Exception as e:
  17. # 将异常写入到日志中
  18. log_helper.error('sql执行失败:' + str(e.args) + ' query:' + str(query))
  19. self.data = None
  20. else:
  21. # 获取数据
  22. try:
  23. if self.cursor.description:
  24. # 在执行insert/update/delete等更新操作时,如果添加了returning,则读取返回数据组合成字典返回
  25. self.data = [dict((self.cursor.description[i][0], value) for i, value in enumerate(row)) for row in self.cursor.fetchall()]
  26. else:
  27. # 如果执行insert/update/delete等更新操作时没有添加returning,则返回影响行数,值为0时表时没有数据被更新
  28. self.data = self.cursor.rowcount
  29. except Exception as e:
  30. # 将异常写入到日志中
  31. log_helper.error('数据获取失败:' + str(e.args) + ' query:' + str(query))
  32. self.data = None
  33. finally:
  34. # 关闭游标
  35. self.cursor.close()
  36. # 记录程序执行结束时间
  37. end_time = time.clock()
  38. # 写入日志
  39. self.write_log(start_time, end_time, query)
  40.  
  41. # 如果有返回数据,则把该数据返回给调用者
  42. return self.data

  最后一个是记录超时sql语句到日志方法,这里我将大于0.1秒的sql语句都记录下来

  1. def write_log(self, start_time, end_time, sql):
  2. """记录Sql执行超时日志"""
  3. t = end_time - start_time
  4. if (t) > 0.1:
  5. content = ' '.join(('run time:', str(t), 's sql:', sql))
  6. log_helper.info(content)

  完成的db_helper.py代码

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import psycopg2
  5. import time
  6. from io import StringIO
  7. from common import log_helper, file_helper
  8.  
  9. class PgHelper(object):
  10. """postgresql数据库操作类"""
  11.  
  12. def __init__(self, db, is_output_sql):
  13. self.connect = None
  14. self.cursor = None
  15. # 初始化数据库参数
  16. self.db_name = db.get('db_name', '')
  17. self.db_user = db.get('db_user', '')
  18. self.db_pass = db.get('db_pass', '')
  19. self.db_host = db.get('db_host', '')
  20. self.db_port = db.get('db_port', '')
  21. # 是否将所有要执行的Sql语句输出到日志里
  22. self.is_output_sql = is_output_sql
  23.  
  24. def open_conn(self):
  25. """连接数据库,并建立游标"""
  26. try:
  27. if not self.connect:
  28. self.connect = psycopg2.connect(database=self.db_name, user=self.db_user, password=self.db_pass,
  29. host=self.db_host, port=self.db_port)
  30. return self.connect
  31. except Exception as e:
  32. log_helper.error('连接数据库失败:' + str(e.args))
  33. return False
  34.  
  35. def close_conn(self):
  36. """关闭postgresql数据库链接"""
  37. # 关闭游标
  38. try:
  39. if self.cursor:
  40. self.cursor.close()
  41. except Exception:
  42. pass
  43. # 关闭数据库链接
  44. try:
  45. if self.connect:
  46. self.connect.close()
  47. except Exception:
  48. pass
  49.  
  50. def __enter__(self):
  51. """初始化数据库链接"""
  52. self.open_conn()
  53. return self
  54.  
  55. def __exit__(self, type, value, trace):
  56. """关闭postgresql数据库链接"""
  57. self.close_conn()
  58.  
  59. def rollback(self):
  60. """回滚操作"""
  61. try:
  62. # 异常时,进行回滚操作
  63. if self.connect:
  64. self.connect.rollback()
  65. except Exception as e:
  66. log_helper.error('回滚操作失败:' + str(e.args))
  67.  
  68. def commit(self):
  69. """提交事务"""
  70. try:
  71. if self.connect:
  72. self.connect.commit()
  73. self.close_conn()
  74. except Exception as e:
  75. log_helper.error('提交事务失败:' + str(e.args))
  76.  
  77. def get_sql(self, query, vars=None):
  78. """获取编译后的sql语句"""
  79. # 记录程序执行开始时间
  80. start_time = time.clock()
  81. try:
  82. # 判断是否记录sql执行语句
  83. if self.is_output_sql:
  84. log_helper.info('sql:' + str(query))
  85. # 建立游标
  86. self.cursor = self.connect.cursor()
  87. # 执行SQL
  88. self.data = self.cursor.mogrify(query, vars)
  89. except Exception as e:
  90. # 将异常写入到日志中
  91. log_helper.error('sql生成失败:' + str(e.args) + ' query:' + str(query))
  92. self.data = '获取编译sql失败'
  93. finally:
  94. # 关闭游标
  95. self.cursor.close()
  96. # 记录程序执行结束时间
  97. end_time = time.clock()
  98. # 写入日志
  99. self.write_log(start_time, end_time, query)
  100.  
  101. return self.data
  102.  
  103. def copy(self, values, table_name, columns):
  104. """
  105. 百万级数据更新函数
  106. :param values: 更新内容,字段之间用\t分隔,记录之间用\n分隔 "1\taaa\tabc\n2\bbb\abc\n"
  107. :param table_name: 要更新的表名称
  108. :param columns: 需要更新的字段名称:例:('id','userame','passwd')
  109. :return:
  110. """
  111. try:
  112. # 建立游标
  113. self.cursor = self.connect.cursor()
  114. self.cursor.copy_from(StringIO(values), table_name, columns=columns)
  115. self.connect.commit()
  116. return True
  117. except Exception as e:
  118. # 将异常写入到日志中
  119. log_helper.error('批量更新失败:' + str(e.args) + ' table:' + table_name)
  120. finally:
  121. # 关闭游标
  122. self.cursor.close()
  123.  
  124. def execute(self, query, vars=None):
  125. """执行sql语句查询,返回结果集或影响行数"""
  126. if not query:
  127. return None
  128. # 记录程序执行开始时间
  129. start_time = time.clock()
  130. try:
  131. # 判断是否记录sql执行语句
  132. if self.is_output_sql:
  133. log_helper.info('sql:' + str(query))
  134. # 建立游标
  135. self.cursor = self.connect.cursor()
  136. # 执行SQL
  137. result = self.cursor.execute(query, vars)
  138. print(str(result))
  139. except Exception as e:
  140. # 将异常写入到日志中
  141. log_helper.error('sql执行失败:' + str(e.args) + ' query:' + str(query))
  142. self.data = None
  143. else:
  144. # 获取数据
  145. try:
  146. if self.cursor.description:
  147. # 在执行insert/update/delete等更新操作时,如果添加了returning,则读取返回数据组合成字典返回
  148. self.data = [dict((self.cursor.description[i][0], value) for i, value in enumerate(row)) for row in self.cursor.fetchall()]
  149. else:
  150. # 如果执行insert/update/delete等更新操作时没有添加returning,则返回影响行数,值为0时表时没有数据被更新
  151. self.data = self.cursor.rowcount
  152. except Exception as e:
  153. # 将异常写入到日志中
  154. log_helper.error('数据获取失败:' + str(e.args) + ' query:' + str(query))
  155. self.data = None
  156. finally:
  157. # 关闭游标
  158. self.cursor.close()
  159. # 记录程序执行结束时间
  160. end_time = time.clock()
  161. # 写入日志
  162. self.write_log(start_time, end_time, query)
  163.  
  164. # 如果有返回数据,则把该数据返回给调用者
  165. return self.data
  166.  
  167. def write_log(self, start_time, end_time, sql):
  168. """记录Sql执行超时日志"""
  169. t = end_time - start_time
  170. if (t) > 0.1:
  171. content = ' '.join(('run time:', str(t), 's sql:', sql))
  172. log_helper.info(content)

  测试代码

  1. #!/usr/bin/evn python
  2. # coding=utf-8
  3.  
  4. import unittest
  5. from common import db_helper
  6. from config import db_config
  7.  
  8. class DbHelperTest(unittest.TestCase):
  9. """数据库操作包测试类"""
  10.  
  11. def setUp(self):
  12. """初始化测试环境"""
  13. print('------ini------')
  14.  
  15. def tearDown(self):
  16. """清理测试环境"""
  17. print('------clear------')
  18.  
  19. def test(self):
  20. # 使用with方法,初始化数据库连接
  21. with db_helper.PgHelper(db_config.DB, db_config.IS_OUTPUT_SQL) as db:
  22. # 设置sql执行语句
  23. sql = """insert into product (name, code) values (%s, %s) returning id"""
  24. # 设置提交参数
  25. vars = ('张三', '')
  26. # 生成sql语句,并打印到控制台
  27. print(db.get_sql(sql, vars))
  28.  
  29. db.execute('select * from product where id=1000')
  30. db.execute('insert into product (name, code) values (%s, %s) returning id', ('张三', ''))
  31. db.commit()
  32.  
  33. if __name__ == '__main__':
  34. unittest.main()

版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

python开发QQ群:669058475(本群已满)、733466321(可以加2群)    作者博客:http://www.cnblogs.com/EmptyFS/

我的第一个python web开发框架(25)——定制ORM(一)的更多相关文章

  1. 我的第一个python web开发框架(41)——总结

    我的第一个python web开发框架系列博文从17年6.7月份开始写(存了近十章稿留到9月份才开始发布),到今天结束,一年多时间,想想真不容易啊. 整个过程断断续续,中间有段时间由于工作繁忙停了好长 ...

  2. 我的第一个python web开发框架(14)——后台管理系统登录功能

    接下来正式进入网站的功能开发.要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX. 在进行接口开发之前, ...

  3. 我的第一个python web开发框架(1)——前言

    由于之前经验不是很丰富,写的C#系统太过复杂,所以一直想重写,但学的越多越觉得自己懂的越少,越觉的底气不足.所以一直不敢动手,在内心深处对自己讲,要静下心来认真学习,继续沉淀沉淀.这两年多以来找各种机 ...

  4. 我的第一个python web开发框架(3)——怎么开始?

    小白与小美公司经过几次接触商谈,好不容易将外包签订了下来,准备开始大干一场.不过小白由于没有太多的项目经验,学过python懂得python的基本语法,在公司跟着大家做过简单功能,另外还会一些HTML ...

  5. 我的第一个python web开发框架(22)——一个安全小事故

    在周末的一个早上,小白还在做着美梦,就收到了小美的连环追魂call,电话一直响个不停. 小白打着哈欠拿起电话:早上好美女. 小美:出事了出事了,我们公司网站一早访问是一片空白,什么内容都没有了,你赶急 ...

  6. 我的第一个python web开发框架(10)——工具函数包说明(一)

    PS:原先是想直接进入功能开发,要用到什么函数时再创建,这样也容易熟悉每个函数的由来和使用方法,但考虑到这样操作,到时会经常在不同文件间切换,不好描述,容易造成混乱,所以还是使用函数库这种方式来说明. ...

  7. 我的第一个python web开发框架(2)——一个简单的小外包

    第一部分说明 第一部分大概有20来章,主要讲的是一些开发常识.开发前中后期准备内容.开发环境与服务器部署环境安装设置.python基础框架结构与功能等内容,代码会比较简单. 本系列会以故事的方式,向大 ...

  8. 我的第一个python web开发框架(6)——第一个Hello World

    小白中午听完老菜讲的那些话后一直在思考,可想来想去还是一头雾水,晕晕呼呼的一知半解,到最后还是想不明白,心想:老大讲的太高深了,只能听懂一半半,看来只能先记下来,将明白的先做,不明白的等以后遇到再学. ...

  9. 我的第一个python web开发框架(7)——本地部署前端访问服务器

    PS:本系列内容进度节奏会放的很慢,每次知识点都尽量少一点,这样大家接触的知识点少了,会更容易理解,因为少即是多.另外,对于后面代码部分,虽然尽量不用那些复杂的封装和类,但它并不表示看了就能全部记住, ...

随机推荐

  1. BBS论坛(二十三)

    23.添加板块 (1)apps/models class BoardModel(db.Model): __tablename__ = 'board' id = db.Column(db.Integer ...

  2. 了解 HTTPS,读这篇文章就够了

    今天接到个活儿,让我科普 HTTPS .讲 HTTP 我都“方”,想要通俗易懂的说完 HTTPS, 我有点“圆”.在讲什么是 HTTPS 之前,我们先来看个漫画.   △ 图片来源于阮一峰的网络日志 ...

  3. Qt窗口定制

    qt中的QWidget窗口支持窗体绘制,但是不支持窗口标题栏绘制,想要美观的界面,还需要自己去定制,下面我就介绍一种定制窗体的方法 一个窗口无非就3部分,标题栏.窗体和状态栏,接下来我定制的窗口没有状 ...

  4. PHP分页倒序时,需要注意的问题

    PHP分页倒序请求,如果有新数据加入,下一页会出现重复数据 解决方案: 第一次查询时,给前端返回一个查询时间戳,下一次请求时,把时间戳带过来,只查询比这个时间戳小的数据

  5. intelliJ idea #region 代码折叠

    在intelliJ idea中不仅可以对类.方法等结构的代码进行折叠(ctrl+-)还可以自定义折叠代码.intelliJ支持两种风格的自定义代码折叠,如下: visual studio style ...

  6. 贝叶斯个性化排序(BPR)算法小结

    在矩阵分解在协同过滤推荐算法中的应用中,我们讨论过像funkSVD之类的矩阵分解方法如何用于推荐.今天我们讲另一种在实际产品中用的比较多的推荐算法:贝叶斯个性化排序(Bayesian Personal ...

  7. Jvm垃圾回收器(算法篇)

    在<Jvm垃圾回收器(基础篇)>中我们主要学习了判断对象是否存活还是死亡?两种基础的垃圾回收算法:引用计数法.可达性分析算法.以及Java引用的4种分类:强引用.软引用.弱引用.虚引用.和 ...

  8. leetcode — subsets-ii

    import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Source : https://o ...

  9. python学习第一讲,python简介

    目录 python学习第一讲,python简介 一丶python简介 1.解释型语言与编译型语言 2.python的特点 3.python的优缺点 二丶第一个python程序 1.python源程序概 ...

  10. 痞子衡嵌入式:常用的数据差错控制技术(1)- 重复校验(Repetition Code)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式里数据差错控制技术-重复校验. 在嵌入式应用里,除了最核心的数据处理外,我们还会经常和数据传输打交道.数据传输需要硬件传输接口的支持 ...