jackfrued пре 5 година
родитељ
комит
5f9b9a57d6

+ 62 - 5
Day01-15/15.图像和办公文档处理.md

@@ -110,13 +110,70 @@ Pillow中最为重要的是Image类,读取和处理图像都要通过这个类
 
 ### 处理Excel电子表格
 
-Python的openpyxl模块让我们可以在Python程序中读取和修改Excel电子表格,当然实际工作中,我们可能会用LibreOffice Calc和OpenOffice Calc来处理Excel的电子表格文件,这就意味着openpyxl模块也能处理来自这些软件生成的电子表格。关于openpyxl的使用手册和使用文档可以查看它的[官方文档](https://openpyxl.readthedocs.io/en/stable/#)。
+Python的openpyxl模块让我们可以在Python程序中读取和修改Excel电子表格,由于微软从Office 2007开始使用了新的文件格式,这使得Office Excel和LibreOffice Calc、OpenOffice Calc是完全兼容的,这就意味着openpyxl模块也能处理来自这些软件生成的电子表格。
 
-### 处理Word文档
+```Python
+import datetime
 
-利用python-docx模块,Pytho 可以创建和修改Word文档,当然这里的Word文档不仅仅是指通过微软的Office软件创建的扩展名为docx的文档,LibreOffice Writer和OpenOffice Writer都是免费的字处理软件。
+from openpyxl import Workbook
 
+wb = Workbook()
+ws = wb.active
 
-### 处理PDF文档
+ws['A1'] = 42
+ws.append([1, 2, 3])
+ws['A2'] = datetime.datetime.now()
 
-PDF是Portable Document Format的缩写,使用.pdf作为文件扩展名。接下来我们就研究一下如何通过Python实现从PDF读取文本内容和从已有的文档生成新的PDF文件。
+wb.save("sample.xlsx")
+```
+
+### 处理Word文档
+
+利用python-docx模块,Python可以创建和修改Word文档,当然这里的Word文档不仅仅是指通过微软的Office软件创建的扩展名为docx的文档,LibreOffice Writer和OpenOffice Writer都是免费的字处理软件。
+
+```Python
+from docx import Document
+from docx.shared import Inches
+
+document = Document()
+
+document.add_heading('Document Title', 0)
+
+p = document.add_paragraph('A plain paragraph having some ')
+p.add_run('bold').bold = True
+p.add_run(' and some ')
+p.add_run('italic.').italic = True
+
+document.add_heading('Heading, level 1', level=1)
+document.add_paragraph('Intense quote', style='Intense Quote')
+
+document.add_paragraph(
+    'first item in unordered list', style='List Bullet'
+)
+document.add_paragraph(
+    'first item in ordered list', style='List Number'
+)
+
+document.add_picture('monty-truth.png', width=Inches(1.25))
+
+records = (
+    (3, '101', 'Spam'),
+    (7, '422', 'Eggs'),
+    (4, '631', 'Spam, spam, eggs, and spam')
+)
+
+table = document.add_table(rows=1, cols=3)
+hdr_cells = table.rows[0].cells
+hdr_cells[0].text = 'Qty'
+hdr_cells[1].text = 'Id'
+hdr_cells[2].text = 'Desc'
+for qty, id, desc in records:
+    row_cells = table.add_row().cells
+    row_cells[0].text = str(qty)
+    row_cells[1].text = id
+    row_cells[2].text = desc
+
+document.add_page_break()
+
+document.save('demo.docx')
+```

+ 6 - 5
Day16-20/16-20.Python语言进阶.md

@@ -792,11 +792,11 @@
   Python使用了自动化内存管理,这种管理机制以**引用计数**为基础,同时也引入了**标记-清除**和**分代收集**两种机制为辅的策略。
 
   ```C
-  typedef struct_object {
+  typedef struct _object {
       /* 引用计数 */
       int ob_refcnt;
       /* 对象指针 */
-      struct_typeobject *ob_type;
+      struct _typeobject *ob_type;
   } PyObject;
   ```
 
@@ -1166,12 +1166,12 @@ Python中实现并发编程的三种方案:多线程、多进程和异步I/O
   import threading
   
   
-  class Account():
+  class Account:
       """银行账户"""
   
       def __init__(self, balance=0):
           self.balance = balance
-          lock = threading.Lock()
+          lock = threading.RLock()
           self.condition = threading.Condition(lock)
   
       def withdraw(self, money):
@@ -1212,9 +1212,10 @@ Python中实现并发编程的三种方案:多线程、多进程和异步I/O
   
   def main():
       account = Account()
-      with ThreadPoolExecutor(max_workers=10) as pool:
+      with ThreadPoolExecutor(max_workers=15) as pool:
           for _ in range(5):
               pool.submit(add_money, account)
+          for _ in range(10):
               pool.submit(sub_money, account)
   
   

+ 3 - 1
Day31-35/31-35.玩转Linux操作系统.md

@@ -136,7 +136,7 @@ Linux系统的命令通常都是如下所示的格式:
 
 4. 清除屏幕上显示的内容 - **clear**。
 
-5. 查看帮助文档 - **man** / **info** / **help** / **apropos**。
+5. 查看帮助文档 - **man** / **info** / **--help** / **apropos**。
    ```Shell
    [root@izwz97tbgo9lkabnat2lo8z ~]# ps --help
    Usage:
@@ -1788,6 +1788,8 @@ echo '结果: '$sum
 
 ```Shell
 #!/usr/bin/bash
+printf '输入文件夹名: '
+read dir
 printf '输入文件名: '
 read file
 printf '输入文件数量(<1000): '

+ 3 - 3
Day36-40/36-38.关系型数据库MySQL.md

@@ -551,9 +551,9 @@ MySQL在过去由于性能高、成本低、可靠性好,已经成为最流行
    ```SQL
    -- 插入学院数据
    insert into tb_college (collname, collintro) values 
-   ('计算机学院', '创建于1956年是我国首批建立计算机专业。学院现有计算机科学与技术一级学科和网络空间安全一级学科博士学位授予权,其中计算机科学与技术一级学科具有博士后流动站。计算机科学与技术一级学科在2017年全国第四轮学科评估中评为A;2019 U.S.News全球计算机学科排名26名;ESI学科排名0.945‰,进入全球前1‰,位列第43位。'),
-   ('外国语学院', '1998年浙江大学、杭州大学、浙江农业大学、浙江医科大学四校合并,成立新的浙江大学。1999年原浙江大学外语系、原杭州大学外国语学院、原杭州大学大外部、原浙江农业大学公外部、原浙江医科大学外语教学部合并,成立浙江大学外国语学院。2003年学院更名为浙江大学外国语言文化与国际交流学院。'),
-   ('经济管理学院', '四川大学经济学院历史悠久、传承厚重,其前身是创办于1905年的四川大学经济科,距今已有100多年的历史。已故著名经济学家彭迪先、张与九、蒋学模、胡寄窗、陶大镛、胡代光,以及当代著名学者刘诗白等曾先后在此任教或学习。在长期的办学过程中,学院坚持以马克思主义的立场、观点、方法为指导,围绕建设世界一流经济学院的奋斗目标,做实“两个伟大”深度融合,不断提高党的建设质量与科学推进一流事业深度融合。');
+   ('计算机学院', '计算机学院1958年设立计算机专业,1981年建立计算机科学系,1998年设立计算机学院,2005年5月,为了进一步整合教学和科研资源,学校决定,计算机学院和软件学院行政班子合并统一运作、实行教学和学生管理独立运行的模式。 学院下设三个系:计算机科学与技术系、物联网工程系、计算金融系;两个研究所:图象图形研究所、网络空间安全研究院(2015年成立);三个教学实验中心:计算机基础教学实验中心、IBM技术中心和计算机专业实验中心。'),
+   ('外国语学院', '四川大学外国语学院设有7个教学单位,6个文理兼收的本科专业;拥有1个一级学科博士授予点,3个二级学科博士授予点,5个一级学科硕士学位授权点,5个二级学科硕士学位授权点,5个硕士专业授权领域,同时还有2个硕士专业学位(MTI)专业;有教职员工210余人,其中教授、副教授80余人,教师中获得中国国内外名校博士学位和正在职攻读博士学位的教师比例占专任教师的60%以上。'),
+   ('经济管理学院', '四川大学经济学院前身是创办于1905年的四川大学经济科;已故经济学家彭迪先、张与九、蒋学模、胡寄窗、陶大镛、胡代光,以及当代学者刘诗白等曾先后在此任教或学习;1905年,四川大学设经济科;1924年,四川大学经济系成立;1998年,四川大学经济管理学院变更为四川大学经济学院。');
    
    -- 插入学生数据
    insert into tb_student (stuid, stuname, stusex, stubirth, stuaddr, collid) values

+ 55 - 54
Day36-40/code/SRS_create_and_init.sql

@@ -2,7 +2,7 @@
 drop database if exists school;
 
 -- 创建名为school的数据库并设置默认的字符集和排序方式
-create database school default charset utf8 collate utf8_bin;
+create database school default charset utf8;
 
 -- 切换到school数据库上下文环境
 use school;
@@ -10,35 +10,32 @@ use school;
 -- 创建学院表
 create table tb_college
 (
-collid int not null auto_increment comment '编号',
-collname varchar(50) not null comment '名称',
-collmaster varchar(20) not null comment '院长',
-collweb varchar(511) default '' comment '网站',
+collid 		int auto_increment comment '编号',
+collname 	varchar(50) not null comment '名称',
+collintro 	varchar(500) default '' comment '介绍',
 primary key (collid)
 );
 
 -- 创建学生表
 create table tb_student
 (
-stuid int not null comment '学号',
-stuname varchar(20) not null comment '姓名',
-stusex bit default 1 comment '性别',
-stubirth date not null comment '出生日期',
-stuaddr varchar(255) default '' comment '籍贯',
-collid int not null comment '所属学院',
+stuid 		int not null comment '学号',
+stuname 	varchar(20) not null comment '姓名',
+stusex 		boolean default 1 comment '性别',
+stubirth 	date not null comment '出生日期',
+stuaddr 	varchar(255) default '' comment '籍贯',
+collid 		int not null comment '所属学院',
 primary key (stuid),
 foreign key (collid) references tb_college (collid)
 );
 
--- alter table tb_student add constraint fk_student_collid foreign key (collid) references tb_college (collid);
-
 -- 创建教师表
 create table tb_teacher
 (
-teaid int not null comment '工号',
-teaname varchar(20) not null comment '姓名',
-teatitle varchar(10) default '助教' comment '职称',
-collid int not null comment '所属学院',
+teaid 		int not null comment '工号',
+teaname 	varchar(20) not null comment '姓名',
+teatitle 	varchar(10) default '助教' comment '职称',
+collid 		int not null comment '所属学院',
 primary key (teaid),
 foreign key (collid) references tb_college (collid)
 );
@@ -46,48 +43,54 @@ foreign key (collid) references tb_college (collid)
 -- 创建课程表
 create table tb_course
 (
-couid int not null comment '编号',
-couname varchar(50) not null comment '名称',
-coucredit int not null comment '学分',
-teaid int not null comment '授课老师',
+couid 		int not null comment '编号',
+couname 	varchar(50) not null comment '名称',
+coucredit 	int not null comment '学分',
+teaid 		int not null comment '授课老师',
 primary key (couid),
 foreign key (teaid) references tb_teacher (teaid)
 );
 
 -- 创建选课记录表
-create table tb_score
+create table tb_record
 (
-scid int auto_increment comment '选课记录编号',
-stuid int not null comment '选课学生',
-couid int not null comment '所选课程',
-scdate datetime comment '选课时间日期',
-scmark decimal(4,1) comment '考试成绩',
-primary key (scid),
-foreign key (stuid) references tb_student (stuid),
-foreign key (couid) references tb_course (couid)
+recid 		int auto_increment comment '选课记录编号',
+sid 		int not null comment '选课学生',
+cid 		int not null comment '所选课程',
+seldate 	datetime default now() comment '选课时间日期',
+score 		decimal(4,1) comment '考试成绩',
+primary key (recid),
+foreign key (sid) references tb_student (stuid),
+foreign key (cid) references tb_course (couid),
+unique (sid, cid)
 );
 
--- 添加唯一性约束(一个学生选某个课程只能选一次)
-alter table tb_score add constraint uni_score_stuid_couid unique (stuid, couid);
-
 -- 插入学院数据
-insert into tb_college (collname, collmaster, collweb) values 
-('计算机学院', '左冷禅', 'http://www.abc.com'),
-('外国语学院', '岳不群', 'http://www.xyz.com'),
-('经济管理学院', '风清扬', 'http://www.foo.com');
+insert into tb_college (collname, collintro) values 
+('计算机学院', '计算机学院1958年设立计算机专业,1981年建立计算机科学系,1998年设立计算机学院,2005年5月,为了进一步整合教学和科研资源,学校决定,计算机学院和软件学院行政班子合并统一运作、实行教学和学生管理独立运行的模式。 学院下设三个系:计算机科学与技术系、物联网工程系、计算金融系;两个研究所:图象图形研究所、网络空间安全研究院(2015年成立);三个教学实验中心:计算机基础教学实验中心、IBM技术中心和计算机专业实验中心。'),
+('外国语学院', '四川大学外国语学院设有7个教学单位,6个文理兼收的本科专业;拥有1个一级学科博士授予点,3个二级学科博士授予点,5个一级学科硕士学位授权点,5个二级学科硕士学位授权点,5个硕士专业授权领域,同时还有2个硕士专业学位(MTI)专业;有教职员工210余人,其中教授、副教授80余人,教师中获得中国国内外名校博士学位和正在职攻读博士学位的教师比例占专任教师的60%以上。'),
+('经济管理学院', '四川大学经济学院前身是创办于1905年的四川大学经济科;已故经济学家彭迪先、张与九、蒋学模、胡寄窗、陶大镛、胡代光,以及当代学者刘诗白等曾先后在此任教或学习;1905年,四川大学设经济科;1924年,四川大学经济系成立;1998年,四川大学经济管理学院变更为四川大学经济学院。');
 
 -- 插入学生数据
-insert into tb_student (stuid, stuname, stusex, stubirth, stuaddr, collid) values
-(1001, '杨逍', 1, '1990-3-4', '四川成都', 1),
-(1002, '任我行', 1, '1992-2-2', '湖南长沙', 1),
-(1033, '王语嫣', 0, '1989-12-3', '四川成都', 1),
-(1572, '岳不群', 1, '1993-7-19', '陕西咸阳', 1),
-(1378, '纪嫣然', 0, '1995-8-12', '四川绵阳', 1),
-(1954, '林平之', 1, '1994-9-20', '福建莆田', 1),
-(2035, '东方不败', 1, '1988-6-30', null, 2),
-(3011, '林震南', 1, '1985-12-12', '福建莆田', 3),
-(3755, '项少龙', 1, '1993-1-25', null, 3),
-(3923, '杨不悔', 0, '1985-4-17', '四川成都', 3);
+insert into tb_student (stuid, stuname, stusex, stubirth, stuaddr, collid) 
+values
+	(1001, '杨逍', 1, '1990-3-4', '四川成都', 1),
+	(1002, '任我行', 1, '1992-2-2', '湖南长沙', 1),
+	(1033, '王语嫣', 0, '1989-12-3', '四川成都', 1),
+	(1572, '岳不群', 1, '1993-7-19', '陕西咸阳', 1),
+	(1378, '纪嫣然', 0, '1995-8-12', '四川绵阳', 1),
+	(1954, '林平之', 1, '1994-9-20', '福建莆田', 1),
+	(2035, '东方不败', 1, '1988-6-30', null, 2),
+	(3011, '林震南', 1, '1985-12-12', '福建莆田', 3),
+	(3755, '项少龙', 1, '1993-1-25', null, 3),
+	(3923, '杨不悔', 0, '1985-4-17', '四川成都', 3),
+	(4040, '炼腰的隔壁老王', 1, '1989-1-1', '四川成都', 2);
+
+-- 删除学生数据
+delete from tb_student where stuid=4040;
+
+-- 更新学生数据
+update tb_student set stuname='杨过', stuaddr='湖南长沙' where stuid=1001;
 
 -- 插入老师数据
 insert into tb_teacher (teaid, teaname, teatitle, collid) values 
@@ -110,7 +113,7 @@ insert into tb_course (couid, couname, coucredit, teaid) values
 (9999, '审计学', 3, 3366);
 
 -- 插入选课数据
-insert into tb_score (stuid, couid, scdate, scmark) values 
+insert into tb_record (sid, cid, seldate, score) values 
 (1001, 1111, '2017-09-01', 95),
 (1001, 2222, '2017-09-01', 87.5),
 (1001, 3333, '2017-09-01', 100),
@@ -125,9 +128,9 @@ insert into tb_score (stuid, couid, scdate, scmark) values
 (1378, 1111, '2017-09-05', 82),
 (1378, 7777, '2017-09-02', 65.5),
 (2035, 7777, '2018-09-03', 88),
-(2035, 9999, curdate(), null),
-(3755, 1111, date(now()), null),
-(3755, 8888, date(now()), null),
+(2035, 9999, default, null),
+(3755, 1111, default, null),
+(3755, 8888, default, null),
 (3755, 9999, '2017-09-01', 92);
 
 -- 查询所有学生信息
@@ -227,8 +230,6 @@ select stuname, couname, scmark from tb_student t1 inner join tb_score t3 on t1.
 
 select stuname, couname, scmark from tb_student t1 inner join tb_score t3 on t1.stuid=t3.stuid inner join tb_course t2 on t2.couid=t3.couid where scmark is not null order by scmark desc limit 10, 5;
 
--- 单表:65535TB
--- 单列:4G - LONGBLOB (Binary Large OBject) / LONGTEXT
 -- 查询选课学生的姓名和平均成绩(子查询和连接查询)
 select stuname, avgmark from tb_student t1, (select stuid, avg(scmark) as avgmark from tb_score group by stuid) t2 where t1.stuid=t2.stuid;
 

+ 4 - 4
Day41-55/42.深入模型.md

@@ -132,8 +132,6 @@
        class Meta:
            managed = False
            db_table = 'tb_subject'
-           verbose_name = '学科'
-           verbose_name_plural = '学科'
    
    
    class Teacher(models.Model):
@@ -151,7 +149,7 @@
            managed = False
            db_table = 'tb_teacher'
    ```
-
+   
    > **说明**:模型类都直接或间接继承自`Model`类,模型类跟关系型数据库的二维表对应,模型对象跟表中的记录对应,模型对象的属性跟表中的字段对应。如果对上面模型类的属性定义不是特别理解,可以看看本文后面提供的“模型定义参考”部分的内容。
 
 ### 使用ORM完成模型的CRUD操作
@@ -205,6 +203,8 @@ Subject.objects.filter(name='Python全栈+人工智能')
 
 # 查询名称包含“全栈”的学科(模糊查询)
 Subject.objects.filter(name__contains='全栈')
+Subject.objects.filter(name__startswith='全栈')
+Subject.objects.filter(name__endswith='全栈')
 
 # 查询所有热门学科
 Subject.objects.filter(is_hot=True)
@@ -513,7 +513,7 @@ Teacher.objects.filter(subject__name__contains='全栈')
                     <div>
                         <span><strong>姓名:{{ teacher.name }}</strong></span>
                         <span>性别:{{ teacher.sex | yesno:'男,女' }}</span>
-                        <span>出生日期:{{ teacher.birth }}</span>
+                        <span>出生日期:{{ teacher.birth | date:'Y年n月j日'}}</span>
                     </div>
                     <div class="intro">{{ teacher.intro }}</div>
                     <div class="comment">

+ 1 - 1
Day41-55/45.制作报表.md

@@ -8,7 +8,7 @@
 报表 = 多样的格式 + 动态的数据
 ```
 
-有很多的三方库支持在Python程序中写Excel文件,包括[`xlwt`](<https://xlwt.readthedocs.io/en/latest/>)、[`xlwings`](<https://docs.xlwings.org/en/latest/quickstart.html>)、[`openpyxl`](<https://openpyxl.readthedocs.io/en/latest/>)、[`xlswriter`](<https://xlsxwriter.readthedocs.io/>)、[`pandas`](<http://pandas.pydata.org/>)等,其中的xlwt虽然只支持写xls格式的Excel文件,但在性能方面的表现还是不错的。下面我们就以`xlwt`为例,来演示如何在Django项目中导出Excel报表。
+有很多的三方库支持在Python程序中写Excel文件,包括[`xlwt`](<https://xlwt.readthedocs.io/en/latest/>)、[`xlwings`](<https://docs.xlwings.org/en/latest/quickstart.html>)、[`openpyxl`](<https://openpyxl.readthedocs.io/en/latest/>)、[`xlswriter`](<https://xlsxwriter.readthedocs.io/>)等,其中的xlwt虽然只支持写xls格式的Excel文件,但在性能方面的表现还是不错的。下面我们就以`xlwt`为例,来演示如何在Django项目中导出Excel报表。
 
 安装`xlwt`。
 

+ 2 - 1
Day41-55/48.前后端分离开发入门.md

@@ -174,4 +174,5 @@ class SubjectMapper(ModelMapper):
 
 前后端分离的开发需要将前端页面作为静态资源进行部署,项目实际上线的时候,我们会对整个Web应用进行动静分离,静态资源通过Nginx或Apache服务器进行部署,生成动态内容的Python程序部署在uWSGI或者Gunicorn服务器上,对动态内容的请求由Nginx或Apache路由到uWSGI或Gunicorn服务器上。
 
-在开发阶段,我们通常会使用Django自带的测试服务器,如果要尝试前后端分离,可以先将静态页面放在之前创建的放静态资源的目录下,具体的做法可以参考[项目完整代码](https://gitee.com/jackfrued/django19062)。
+在开发阶段,我们通常会使用Django自带的测试服务器,如果要尝试前后端分离,可以先将静态页面放在之前创建的放静态资源的目录下,具体的做法可以参考[项目完整代码](https://gitee.com/jackfrued/django19062)。
+

+ 15 - 24
Day41-55/49.RESTful架构和DRF入门.md

@@ -170,7 +170,7 @@ urlpatterns = [
     <div id="container">
         <h1>{{ subject.name }}学科的老师信息</h1>
         <hr>
-        <h2 v-if="teachers.length == 0">暂无该学科老师信息</h2>
+        <h2 v-if="loaded && teachers.length == 0">暂无该学科老师信息</h2>
         <div class="teacher" v-for="teacher in teachers">
             <div class="photo">
                 <img :src="'/static/images/' + teacher.photo" height="140" alt="">
@@ -183,23 +183,24 @@ urlpatterns = [
                 </div>
                 <div class="intro">{{ teacher.intro }}</div>
                 <div class="comment">
-                    <a href="" @click.prevent="praise(teacher)">好评</a>&nbsp;&nbsp;
+                    <a href="" @click.prevent="vote(teacher, true)">好评</a>&nbsp;&nbsp;
                     (<strong>{{ teacher.good_count }}</strong>)
                     &nbsp;&nbsp;&nbsp;&nbsp;
-                    <a href="" @click.prevent="criticize(teacher)">差评</a>&nbsp;&nbsp;
+                    <a href="" @click.prevent="vote(teacher, false)">差评</a>&nbsp;&nbsp;
                     (<strong>{{ teacher.bad_count }}</strong>)
                 </div>
             </div>
         </div>
-        <a href="/">返回首页</a>
+        <a href="/static/html/subjects.html">返回首页</a>
     </div>
     <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
     <script>
         let app = new Vue({
             el: '#container',
             data: {
-                subject: null,
-                teachers: []
+                subject: {},
+                teachers: [],
+                loaded: false
             },
             created() {
                 fetch('/api/teachers/' + location.search)
@@ -215,27 +216,18 @@ urlpatterns = [
                 }
             },
             methods: {
-                praise(teacher) {
-                    fetch('/praise/?tno=' + teacher.no)
-                        .then(resp => resp.json())
-                        .then(json => {
-                            if (json.code === 20000) {
+               vote(teacher, flag) {
+                    let url = flag? '/praise/' : '/criticize/'
+                    url += '?tno=' + teacher.no
+                    fetch(url).then(resp => resp.json()).then(json => {
+                        if (json.code === 10000) {
+                            if (flag) {
                                 teacher.good_count = json.count
                             } else {
-                                alert(json.mesg)
-                            }
-                        })
-                },
-                criticize(teacher) {
-                    fetch('/criticize/?tno=' + teacher.no)
-                        .then(resp => resp.json())
-                        .then(json => {
-                            if (json.code === 20000) {
                                 teacher.bad_count = json.count
-                            } else {
-                                alert(json.mesg)
                             }
-                        })
+                        }
+                    })
                 }
             }
         })
@@ -352,4 +344,3 @@ except InvalidTokenError:
 ```
 
 相信通过上面的讲解,大家已经可以自行完成对投票项目用户登录功能的修改,如果有什么疑惑,可以参考我的代码,点击[地址一](https://github.com/jackfrued/vote)或[地址二](https://gitee.com/jackfrued/vote)可以打开项目仓库的页面。
-

+ 37 - 0
Day41-55/50.RESTful架构和DRF进阶.md

@@ -1,3 +1,40 @@
 ## RESTful架构和DRF进阶
 
+除了上一节讲到的方法,使用DRF创建REST风格的数据接口还有CBV(基于类的视图)的方式。使用CBV创建数据接口的特点是代码简单,开发效率高,但是没有FBV(基于函数的视图)灵活,因为使用FBV的方式,数据接口对应的视图函数执行什么样的代码以及返回什么的数据是高度可定制的。下面我们以定制学科的数据接口为例,讲解通过CBV方式定制数据接口的具体做法。
+
+### 使用ModelViewSet
+
+修改之前项目中的`polls/views.py`,去掉`show_subjects`视图函数,添加一个名为`SubjectViewSet`的类。
+
+```Python
+class SubjectViewSet(ModelViewSet):
+    queryset = Subject.objects.all()
+    serializer_class = SubjectSerializer
+```
+
+通过查看`ModelViewSet`类的源代码可以发现,该类共有6个父类,其中前5个父类分别实现创建学科、获取指定学科、更新指定学科、删除指定学科和获取学科列表的数据接口,对应的方法分别是`create`、`retrieve`、`update`、`destroy`和`list`。由于ModelViewSet的父类中已经实现了这些方法,所以我们几乎没有编写任何代码就完成了学科数据接口的开发,我们要做的仅仅是指出如何获取到学科数据(通过`queryset`属性指定)以及如何序列化学科数据(通过`serializer_class`属性指定)。
+
+```Python
+class ModelViewSet(mixins.CreateModelMixin,
+                   mixins.RetrieveModelMixin,
+                   mixins.UpdateModelMixin,
+                   mixins.DestroyModelMixin,
+                   mixins.ListModelMixin,
+                   GenericViewSet):
+    """
+    A viewset that provides default `create()`, `retrieve()`, `update()`,
+    `partial_update()`, `destroy()` and `list()` actions.
+    """
+    pass
+```
+
+要使用上面的`SubjectViewSet`,需要在`urls.py`文件中进行URL映射。不同于之前的视图函数映射URL的方式,我们需要先创建一个路由器对象并通过该对象注册`SubjectViewSet`,然后将注册成功后生成的URL一并添加到`urlspattern`列表中,代码如下所示。
+
+```Python
+router = DefaultRouter()
+router.register('api/subjects', SubjectViewSet)
+urlpatterns += router.urls
+```
+
+### 使用APIView的子类
 

+ 2 - 0
Day41-55/53.异步任务和定时任务.md

@@ -2,3 +2,5 @@
 
 
 
+ 
+

+ 9 - 0
Day41-55/55.项目上线.md

@@ -1,3 +1,12 @@
 ## 项目上线
 
+### 上线前的检查工作
+
+### 同步代码到云服务器
+
+### WSGI服务器的应用
+
+### Nginx的相关配置
+
+
 

+ 2 - 0
Day56-60/56-60.用FastAPI开发数据接口.md

@@ -0,0 +1,2 @@
+## 用FastAPI开发数据接口
+

+ 0 - 2
Day56-60/56.Flask入门.md

@@ -1,2 +0,0 @@
-## Flask入门
-

+ 0 - 2
Day56-60/57.模板的使用.md

@@ -1,2 +0,0 @@
-## 模板的使用
-

+ 0 - 2
Day56-60/58.表单的处理.md

@@ -1,2 +0,0 @@
-## 表单的处理
-

+ 0 - 2
Day56-60/59.数据库操作.md

@@ -1,2 +0,0 @@
-## 数据库操作
-

+ 0 - 2
Day56-60/60.项目实战.md

@@ -1,2 +0,0 @@
-## 项目实战
-

+ 1 - 1
Day61-65/63.异步化.md → Day61-65/63.Tornado中的异步化.md

@@ -1,4 +1,4 @@
-## 异步化
+## Tornado中的异步化
 
 在前面的例子中,我们并没有对`RequestHandler`中的`get`或`post`方法进行异步处理,这就意味着,一旦在`get`或`post`方法中出现了耗时间的操作,不仅仅是当前请求被阻塞,按照Tornado框架的工作模式,其他的请求也会被阻塞,所以我们需要对耗时间的操作进行异步化处理。
 

+ 3 - 3
Day66-75/67.数据采集和解析.md

@@ -4,7 +4,7 @@
 
 1. 下载数据 - **urllib** / **requests** / **aiohttp** / **httpx**。
 2. 解析数据 - **re** / **lxml** / **beautifulsoup4** / **pyquery**。
-3. 缓存和持久化 - **mysqlclient** / **sqlalchemy** / **peewee**/ **redis** / **pymongo**。
+3. 缓存和持久化 - **mysqlclient** / **sqlalchemy** / **peewee** / **redis** / **pymongo**。
 4. 生成数字签名 - **hashlib**。
 5. 序列化和压缩 - **pickle** / **json** / **zlib**。
 6. 调度器 - **multiprocessing** / **threading** / **concurrent.futures**。
@@ -164,7 +164,7 @@
 6. 设置请求超时。
 
    ```Python
-   requests.get('https://github.com', timeout=0.01)
+   requests.get('https://github.com', timeout=10)
    ```
 
 ### 页面解析
@@ -181,7 +181,7 @@
 
 #### 使用正则表达式解析页面
 
-如果你对正则表达式没有任何的概念,那么推荐先阅读[《正则表达式30分钟入门教程》](),然后再阅读我们之前讲解在Python中如何使用正则表达式一文。
+如果你对正则表达式没有任何的概念,那么推荐先阅读[《正则表达式30分钟入门教程》](https://deerchao.cn/tutorials/regex/regex.htm),然后再阅读我们之前讲解在Python中如何使用正则表达式一文。
 
 下面的例子演示了如何用正则表达式解析“豆瓣电影Top250”中的中文电影名称。
 

+ 78 - 2
Day66-75/70.解析动态内容.md

@@ -14,8 +14,6 @@
 
 那么结论就很简单了,只要我们找到了这些网络API接口,那么就能通过这些接口获取到数据,当然实际开发的时候可能还要对这些接口的参数以及接口返回的数据进行分析,了解每个参数的意义以及返回的JSON数据的格式,这样才能在我们的爬虫中使用这些数据。
 
-
-
 ### 使用Selenium
 
 尽管很多网站对自己的网络API接口进行了保护,增加了获取数据的难度,但是只要经过足够的努力,绝大多数还是可以被逆向工程的,但是在实际开发中,我们可以通过浏览器渲染引擎来避免这些繁琐的工作,WebKit就是一个利用的渲染引擎。
@@ -80,3 +78,81 @@ export PATH=$PATH:/Users/Hao/Downloads/Tools/chromedriver/
 ```
 
 其中`/Users/Hao/Downloads/Tools/chromedriver/ `就是chromedriver所在的路径。当然,更为简单的办法是把chromedriver直接放在虚拟环境中,跟Python解释器位于同一个路径下就可以了。
+
+### WebDriver用法详解
+
+表1. 定位页面元素的方法
+
+
+
+表2. WebDriver的常用属性
+
+| 属性                  | 描述                          |
+| --------------------- | ----------------------------- |
+| current_url           | 当前页面的URL                 |
+| current_window_handle | 当前窗口的句柄(引用)        |
+| name                  | WebDriver实例底层浏览器的名称 |
+| orientation           | 当前设备的方向(横屏、竖屏)  |
+| page_source           | 当前页面的源代码(动态内容)  |
+| title                 | 当前页面的标题                |
+| window_handles        | WebDriver打开的所有窗口的句柄 |
+
+表3. WebDriver的常用方法
+
+| 方法                                | 描述                                   |
+| ----------------------------------- | -------------------------------------- |
+| back() / forward()                  | 在浏览历史记录中后退/前进              |
+| close() / quit()                    | 关闭当前浏览器窗口 / 退出WebDriver实例 |
+| get(url)                            | 加载指定URL的页面到浏览器中            |
+| maximize_window()                   | 将浏览器窗口最大化                     |
+| refresh()                           | 刷新当前页面                           |
+| switch_to_active_element()          | 获得页面上得到焦点的元素               |
+| switch_to_alert()                   | 把焦点切换至弹出的警告框               |
+| set_page_load_timeout(time_to_wait) | 设置页面加载超时时间                   |
+| set_script_timeout(time_to_wait)    | 设置JavaScript执行超时时间             |
+| implicit_wait(time_to_wait)         | 设置等待元素被找到或目标指令完成       |
+
+### WebElement用法
+
+表1. WebElement常用属性
+
+|      |      |
+| ---- | ---- |
+|      |      |
+|      |      |
+|      |      |
+
+表2. WebElement常用方法
+
+|      |      |
+| ---- | ---- |
+|      |      |
+|      |      |
+|      |      |
+|      |      |
+|      |      |
+|      |      |
+|      |      |
+|      |      |
+|      |      |
+
+### Select用法
+
+### Alert用法
+
+### 元素等待机制
+
+#### 隐式等待
+
+#### 显示等待
+
+### 高级特性
+
+#### 鼠标和键盘事件
+
+#### 调用JavaScript
+
+#### 屏幕截图和录制
+
+#### 操作Cookie
+

+ 2 - 1
Day91-100/93.MySQL性能优化.md

@@ -267,4 +267,5 @@ show status like 'slow_queries';
 
 
 
-> **说明**:本章内容参考了网易出品的《深入浅出MySQL》一书,该书和《高性能MySQL》一样,都对MySQL进行了深入细致的讲解,虽然总体感觉后者更加高屋建瓴,但是前者也算得上是提升MySQL技能的佳作(作者的文字功底稍显粗糙,深度也不及后者),建议有兴趣的读者可以阅读这两本书。
+> **说明**:本章内容参考了网易出品的《深入浅出MySQL》一书,该书和《高性能MySQL》一样,都对MySQL进行了深入细致的讲解,虽然总体感觉后者更加高屋建瓴,但是前者也算得上是提升MySQL技能的佳作(作者的文字功底稍显粗糙,深度也不及后者),建议有兴趣的读者可以阅读这两本书。
+

+ 6 - 6
Day91-100/95.使用Django开发商业项目.md

@@ -1649,23 +1649,23 @@ Celery是一个本身不提供队列服务,官方推荐使用RabbitMQ或Redis
 
    ```Python
    # 注册环境变量
-   os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fangtx.settings')
+   os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名.settings')
    
    # 创建Celery实例
    app = celery.Celery(
        'fangtx',
-       broker='amqp://luohao:123456@120.77.222.217:5672/vhost1'
+       broker='amqp://luohao:123456@1.2.3.4:5672/vhost1'
    )
    
    # 从项目的配置文件读取Celery配置信息
-   app.config_from_object('django.conf:settings')
+   # app.config_from_object('django.conf:settings')
    # 从指定的文件(例如celery_config.py)中读取Celery配置信息
    # app.config_from_object('celery_config')
    
    # 让Celery自动从参数指定的应用中发现异步任务/定时任务
-   app.autodiscover_tasks(['common', ])
+   # app.autodiscover_tasks(['common', ])
    # 让Celery自动从所有注册的应用中发现异步任务/定时任务
-   # app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
+   app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
    ```
 
 4. 启动Celery创建woker(消息的消费者)。
@@ -1678,7 +1678,7 @@ Celery是一个本身不提供队列服务,官方推荐使用RabbitMQ或Redis
 
    ```Python
    @app.task
-   def send_email(from, to, cc, subject, content):
+   def send_email(from_user, to_user, cc_user, subject, content):
        pass
    
    

+ 6 - 7
Day91-100/98.项目部署上线和性能调优.md

@@ -413,11 +413,11 @@ events {
 }
 
 # 为HTTP服务配置负载均衡
-http {   
-	upstream fangtx {
-		server 172.18.61.250:801 weight=4;
-		server 172.18.61.250:802 weight=2;
-		server 172.18.61.250:803 weight=2;
+http {
+	upstream xx {
+		server 192.168.1.100 weight=2;
+		server 192.168.1.101 weight=1;
+		server 192.168.1.102 weight=1;
     }
 
 	server {
@@ -782,12 +782,11 @@ class MasterSlaveRouter(object):
 1. 安装Supervisor。
 
    ```Shell
-   pip install virtualenv
    virtualenv -p /usr/bin/python venv
    source venv/bin/activate
    pip install supervisor
    ```
-
+   
 2. 查看Supervisor的配置文件。
 
     ```Shell

+ 4 - 11
README.md

@@ -311,18 +311,11 @@
 - 配置HTTPS
 - 配置域名解析
 
+### Day56~60 - [用FastAPI开发数据接口](./Day56-60/56-60.用FastAPI开发数据接口.md)
 
-### Day56~60 - [实战Flask](./Day56-65)
+- 
 
-#### Day56 - [Flask入门](./Day56-60/56.Flask入门.md) 
-
-#### Day57 - [模板的使用](./Day56-60/57.模板的使用.md) 
-
-#### Day58 - [表单的处理](./Day56-60/58.表单的处理.md) 
-
-#### Day59 - [数据库操作](./Day56-60/59.数据库操作.md)
-
-#### Day60 - [项目实战](./Day56-60/60.项目实战.md)
+- 项目实战:车辆违章查询系统的开发和虚拟化部署
 
 ### Day61~65 - [实战Tornado](./Day61-65)
 
@@ -338,7 +331,7 @@
 - 路由解析
 - 请求处理器
 
-#### Day63 - [异步化](./Day61-65/63.异步化.md)
+#### Day63 - [Tornado中的异步化](./Day61-65/63.Tornado中的异步化.md)
 
 - aiomysql和aioredis的使用