-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathblog.sql
942 lines (811 loc) · 243 KB
/
blog.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
-- MySQL dump 10.13 Distrib 5.7.26, for Win64 (x86_64)
--
-- Host: localhost Database: test_blog
-- ------------------------------------------------------
-- Server version 5.7.26
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `api_email`
--
DROP TABLE IF EXISTS `api_email`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `api_email` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(254) COLLATE utf8_unicode_ci NOT NULL,
`content` longtext COLLATE utf8_unicode_ci NOT NULL,
`create_date` datetime(6) NOT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `api_email`
--
LOCK TABLES `api_email` WRITE;
/*!40000 ALTER TABLE `api_email` DISABLE KEYS */;
/*!40000 ALTER TABLE `api_email` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_advert`
--
DROP TABLE IF EXISTS `page_advert`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_advert` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`href` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`img` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`img_list` longtext COLLATE utf8_unicode_ci,
`is_show` tinyint(1) NOT NULL,
`author` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`abstract` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_advert`
--
LOCK TABLES `page_advert` WRITE;
/*!40000 ALTER TABLE `page_advert` DISABLE KEYS */;
INSERT INTO `page_advert` VALUES (1,'枫枫知道前端基础课程','https://www.bilibili.com/video/BV1MU4y1c7UT','','http://i2.hdslb.com/bfs/archive/63341f77756f9b3b4a538534a7fbd1e83e773720.png',1,'哔哩哔哩','前端课程,简单而不简约'),(3,'枫枫知道个人博客201-300','https://www.bilibili.com/video/BV1sL411T735','','http://i0.hdslb.com/bfs/archive/5c2f3ac6e0395071d52b1545ad787e968f939689.png',1,'枫枫','枫枫知道个人博客201-300'),(2,'枫枫知道个人博客','https://www.bilibili.com/video/BV1yu411276D','','http://i0.hdslb.com/bfs/archive/ea742ba7fce8ad0a20c5ced57475b927f0c23ba8.png',1,'哔哩哔哩','枫枫知道个人博客,基于django开发');
/*!40000 ALTER TABLE `page_advert` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_articles`
--
DROP TABLE IF EXISTS `page_articles`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_articles` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`abstract` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
`content` longtext COLLATE utf8_unicode_ci,
`create_date` datetime(6) DEFAULT NULL,
`change_date` datetime(6) DEFAULT NULL,
`status` int(11) NOT NULL,
`recommend` tinyint(1) NOT NULL,
`look_count` int(11) NOT NULL,
`comment_count` int(11) NOT NULL,
`digg_count` int(11) NOT NULL,
`collects_count` int(11) NOT NULL,
`category` int(11) DEFAULT NULL,
`author` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`source` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`cover_id` int(11) DEFAULT NULL,
`pwd` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`link` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
`word` int(11) NOT NULL,
PRIMARY KEY (`nid`),
KEY `page_articles_cover_id_02b692b0` (`cover_id`)
) ENGINE=MyISAM AUTO_INCREMENT=45 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_articles`
--
LOCK TABLES `page_articles` WRITE;
/*!40000 ALTER TABLE `page_articles` DISABLE KEYS */;
INSERT INTO `page_articles` VALUES (1,'Django路由分发','静态文件显示配置\n在项目根目录下创建一个static目录\n在settings.py中写上\n```python STATIC_URL = \'/static/\'\n/static/代表页','### 静态文件显示配置\n\n1. 在项目根目录下创建一个static目录\n2. 在settings.py中写上\n\n```python\nSTATIC_URL = \'/static/\'\n# /static/代表页面去访问的地址\nSTATICFILES_DIRS = [\n os.path.join(BASE_DIR, \'static\')\n]\n# 这里的static代表它在你项目中的路径\n```\n3. 去访问static下的文件\n\n> /static/12.txt\n\n---\n\n### 正则匹配\n\n普通的路径匹配\n\n```python\npath(\'index/\', views.index),\n# 当请求/index/路径,就会被index/给匹配,去执行index这个视图函数\n# 如果我想匹配/index/下的任意数字,都想被index函数去执行,就没法办到了\n```\n\n正则匹配\n\n```python\nfrom django.urls import path, re_path\nfrom app01 import views\nurlpatterns = [\n re_path(\'index/\\d\\d\\d/\', views.index),\n]\n```\n\n使用正则表达式进行路径匹配\n我去访问/index/123/\n/index/234/\n都会被`index/\\d\\d\\d/`进行成功匹配\n从而去执行index函数\n\n### 正则匹配之无名分组\n\n如果在index函数中,我想接收所匹配的内容,就需要要使用到分组匹配\n\n```python\nre_path(\'index/(\\d\\d\\d\\d)/\', views.index),\n```\n\n将(\\d\\d\\d\\d)匹配的值,传递给index函数,那么index函数就要进行接收\n\n```python\ndef index(request, year):\n print(year)\n return HttpResponse(\'index\')\n```\n\n由于是无名分组,这里index函数的接收参数,可以随便写\n\n### 正则匹配之有名分组\n\n```python\nre_path(\'book/(?P<m>\\d\\d)/\', views.book),\n```\n\n将(?P\\d\\d)匹配的内容以m的关键字传递给book这个函数,那么book这个函数的参数必须是m\n\n```python\ndef book(request, m):\n print(m)\n return HttpResponse(\'月份\')\n```\n\n---\n\n### 多个app的路由分发\n\n使用include进行路由分发\n\n```python\nre_path(\'^app01/\', include(\'app01.urls\')), # /app01/index/\nre_path(\'^app02/\', include(\'app02.urls\')), # /app02/index\n```\n\n> 比如我请求/app02/index,先被^app02/匹配上,\n把我的请求导向到include(\'app02.urls\'))\n\n---\n\n### 登录验证\n\n```python\ndef login(request):\n # 获取get请求参数用这个\n # name = request.GET.get(\'name\')\n # pwd = request.GET.get(\'pwd\')\n # print(name, pwd)\n\n # 获取post请求参数用这个\n name = request.POST.get(\'name\')\n pwd = request.POST.get(\'pwd\')\n print(name, pwd)\n if name == \'fengfeng\' and pwd == \'1234\':\n return redirect(\'/app01/index/\')\n return render(request, \'login.html\')\n```\n\n> 返回三剑客\nrender 返回一个页面\n\n```python\nreturn render(request, \'index.html\') # index.html是在templates中的路径\n```\n\n> HttpResponse 返回字符串\n\n```python\nreturn HttpResponse(\"hello world\") # 直接写要返回的字符串\n```\n\n> redirect 重定向到一个地址\n\n```python\nreturn rediect(\'/login/\') # 直接写跳转的路径,\n# 如果使用了include,也要补全app的路径\n```','2022-01-12 11:15:29.662877','2022-03-10 22:50:05.204966',1,1,27,0,8,0,2,'枫枫','枫枫知道个人博客',3,NULL,NULL,2030),(26,'【项目相关】0208--文章搜索','前端的一些必备知识\n判断类属性是否存在与节点中\nJavaScript let box = document.querySelector(\'.search\') box.classLi','前端的一些必备知识\n\n\n\n判断类属性是否存在与节点中\n\n```JavaScript\nlet box = document.querySelector(\'.search\')\nbox.classList.contains(\'show\')\n```\n\n添加与删除类属性\n\n```JavaScript\nbox.classList.add(\'show\')\nbox.classList.remove(\'show\')\n```\n\njs实现新建标签页跳转\n\n```JavaScript\nwindow.open(url=`/?search=...`, name=\'_blank\')\n```\n\n\n\n\n\nhtml结构\n\n```JavaScript\n<div class=\"search\">\n <input v-model=\"search_key\" type=\"text\" placeholder=\"搜索文章\">\n <button @click=\"show_search\"><i class=\"fa fa-search\"></i></button>\n</div>\n```\n\n一共有四个地方要注意\n\n![](http://python.fengfengzhidao.com/023/20220208130753.png)\n\n![](http://python.fengfengzhidao.com/023/20220208130821.png)\n\n![](http://python.fengfengzhidao.com/023/20220208130805.png)\n\n![](http://python.fengfengzhidao.com/023/20220208130837.png)\n\n这里的js代码比较简单\n\n点击的时候去获取search标签,判断是否存在特定类属性\n\n如果存在就说明是展开状态\n\n如果不存在就说明是收缩状态\n\n```JavaScript\nshow_search() {\n let box = document.querySelector(\'.search\')\n if (!box.classList.contains(\'show_search\')) {\n box.classList.add(\'show_search\')\n } else {\n if (this.search_key){\n window.open(url=`/serach/?key=${this.search_key}`, name=\'_blank\')\n return\n }\n box.classList.remove(\'show_search\')\n }\n}\n```\n\n\n\ncss样式编写\n\ncss部分就比较复杂了,要对应四种状态,搜索框的展开与收缩,以及导航条的显示与隐藏,两两组合,共有四种状态\n\n\n\n我们一一举例\n\n导航条在顶部,搜索框收缩状态,对应的类名为\n\n```CSS\nnav .serach{\n\n}\n```\n\n\n\n导航条在顶部,搜索框展开状态,对应的类名为\n\n```CSS\nnav .show_search{\n\n}\n```\n\n\n\n导航条在其他位置,搜索框收缩状态,对应的类名为\n\n```CSS\n.show_nav .serach{\n\n}\n```\n\n\n\n导航条在其他位置,搜索框展开状态,对应的类名为\n\n```CSS\n.show_nav .show_search{\n\n}\n```\n\n\n\n然后去编写对应的代码\n\n```CSS\nnav .search {\n display: inline-flex;\n\n input {\n border: none;\n padding-left: 10px;\n outline: none;\n width: 0;\n height: 40px;\n border-radius: 5px 0 0 5px;\n transition: all 0.3s;\n opacity: 0;\n }\n\n button {\n width: 50px;\n height: 40px;\n color: white;\n border: none;\n cursor: pointer;\n border-radius: 0 5px 5px 0;\n background-color: rgba(white, 0);\n transition: all 0.3s;\n }\n}\n\nnav .show_search {\n input {\n width: 300px;\n opacity: 1;\n background-color: rgba(white, 0.5);\n\n }\n\n button {\n color: #333333;\n background-color: rgba(white, 0.5);\n\n }\n}\n\n.show_nav .search {\n button {\n color: #333333;\n }\n}\n\n.show_nav .show_search {\n input {\n border-width: 1px 0 1px 1px;\n border-style: solid;\n border-color: #f0eeee;\n }\n\n button {\n border-width: 1px 1px 1px 0;\n border-style: solid;\n border-color: #f0eeee;\n }\n}\n```','2022-02-09 12:27:18.163087','2022-03-10 22:50:05.192955',1,1,138,3,7,1,1,'枫枫','枫枫知道个人博客',4,NULL,NULL,2423),(25,'python基础--模块和包','模块(Module)\n在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。\n为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件','# 模块(Module)\n\n在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。\n\n为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)\n\n**使用模块有什么好处?**\n\n> 最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。\n\n> 使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。\n\n你也许还想到,如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。\n\n举个例子,一个abc.py的文件就是一个名字叫abc的模块,一个xyz.py的文件就是一个名字叫xyz的模块\n\n现在,假设我们的`abc`和`xyz`这两个模块名字与其他模块冲突了,于是我们可以通过包来组织模块,避免冲突。方法是选择一个顶层包名,比如`mycompany`,按照如下目录存放:\n\n```Python\nmycompany\n├─ __init__.py\n├─ abc.py\n└─ xyz.py\n```\n\n引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。现在,`abc.py`模块的名字就变成了`mycompany.abc`,类似的,xyz.py的模块名变成了`mycompany.xyz`。\n\n请注意,每一个包目录下面都会有一个`__init__.py`的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。**init**.py可以是空文件,也可以有Python代码,因为`__init__.py`本身就是一个模块,而它的模块名就是`mycompany`\n\n类似的,可以有多级目录,组成多级层次的包结构。比如如下的目录结构:\n\n```Python\nmycompany\n ├─ web\n │ ├─ __init__.py\n │ ├─ utils.py\n │ └─ www.py\n ├─ __init__.py\n ├─ abc.py\n └─ xyz.py\n```\n\n文件`www.py`的模块名就是`mycompany.web.www`\n\n**注意:** 自己创建模块时要注意命名,不能和Python自带的模块名称冲突。例如,系统自带了sys模块,自己的模块就不可命名为sys.py,否则将无法导入系统自带的sys模块。\n\n## 使用模块\n\n自己创建模块可能还有点难,我们先结合实战案例,如何使用python的标准库\n\nPython的标准库有:\n\n|||\n|-|-|\n|名称|作用|\n|datetime|为日期和时间处理同时提供了简单和复杂的方法。|\n|zlib|直接支持通用的数据打包和压缩格式:zlib,gzip,bz2,zipfile,以及 tarfile|\n|random|提供了生成随机数的工具。|\n|math|为浮点运算提供了对底层C函数库的访问。|\n|os|提供了不少与操作系统相关联的函数。|\n\n\ndatetime库的使用方法\n\n```Python\nfrom datetime import date\n#导入时间库\nnow=date.today()\n#取当前时间\nprint(now)\nbirthday=date(1987,12,3)\nprint(birthday)\nage=now-birthday\n#假设年龄=当前日期-生日日期\nprint(age)\n```\n\n导入库的方式:\n\n1. 使用from导入某个库中的某个函数,在使用的时候不再需要加上库名\n2. 使用impor导入这个库的所有函数,在使用时,要加上库名\n\n我们结合案例分析看看这两种有什么不一样\n\n导入随机模块进行随机取值,第一种使用import\n\n```Python\nimport random\nnum=random.random()\nprint(num)\n# random.random是随机生成一个0~1之间的浮点数 \n```\n\n第一个random是包名,不能省略的\n\n第二种是使用from进行导入具体的函数\n\n```Python\nfrom random import random\nnum=random()\nprint(num)\n```\n\n我们可以看到,我们就可以直接使用这个random函数了,而不再需要使用random.random\n\n### 导入多个模块\n\n```Python\nimport 模块1,模块2,模块3\n```\n\n### **模块改名**\n\n```Python\nimport random as rd\nnum = rd.random()\nprint(num) \n```\n\n我们将random模块取了一个别称rd\n\n我们在调用random模块的时候就可以使用rd进行代替\n\n### 模块、包与库的关系\n\n**python模块是**:\n自我包含并且有组织的代码片段为模块。\n表现形式为:写的代码保存为文件。这个文件就是一个模块。[sample.py](http://sample.py) 其中文件名smaple为模块名字。\n\n**python包是**:\n包是一个有层次的文件目录结构,它定义了由n个模块或n个子包组成的python应用程序执行环境。\n\n通俗一点:包是一个包含__init__.py 文件的目录,该目录下一定得有这个__init__.py文件和其它模块或子包。\n\n**python库是**:\n参考其它编程语言的说法,就是指python中的完成一定功能的代码集合,供用户使用的代码组合。在python中是包和模块的形式。','2022-02-06 11:57:02.618543','2022-03-10 22:50:05.195958',1,1,9,0,19,2,2,'枫枫','枫枫知道个人博客',10,NULL,NULL,2509),(2,'Django反向解析','什么是反向解析\n在上节课中,我们如果要在后台中,使用某个url地址 是需要自己进行设置的 如:\n```python from django.shortcuts import red','#### 什么是反向解析\n\n在上节课中,我们如果要在后台中,使用某个url地址 是需要自己进行设置的 如:\n\n```python\nfrom django.shortcuts import redirect\n\n\ndef login(request):\n ...\n return redirect(\'/login/\')\n# 我们需要自己去写登录成功之后进行跳转的地址,这样其实特别不方便\n# 如果项目稍微大一点,我们就需要去记很多的跳转地址\n```\n\n为什么不一开始就给这些url起一个别名,类似于一个变量名 下次要使用这个url,就直接使用这个变量名即可\n\n```python\npath(\'login/\', views.login, name=\'login\'),\n# 在urls中,进行路由分发的时候,多加一个name参数\n# 那么我们就可以在后端,或者是前端进行使用这个路径了\n```\n\n我们先来看在后端中,怎么接收到这个login地址的\n\n```python\nfrom django.urls import reverse\nfrom django.shortcuts import redirect\n\n\ndef login(request):\n print(reverse(\'login\'))\n # 根据别名反向解析出url\n login_path = reverse(\'login\')\n return redirect(login_path)\n```\n\n那么在前端中,我也想使用这个路径,就需要这么写了\n\n```html\n\n<form action=\"{% url \'login\' %}\" method=\"post\">\n ...\n</form>\n```\n\n`{% url \'login\' %}`是一种专门做反向解析的固定写法,叫模板标签,我们下节课再讲 现在会用即可\n\n#### 名称空间\n\n好了,现在问题又出现了,如果我有多个app\n\n可不可能存在两个一样的别名?\n\n这是完全可能的!!\n\n例如qq的登录,微信的登录\n\n我都要用login这个别名,那么怎么区分出这个别名对应那个app呢?\n\n我们在include进行路由分发的时候,为这个app起一个namespace, 可以理解为,为app起一个别名\n\n```python\nre_path(\'^app01/\', include((\'app01.urls\', \'app01\'))), # /app01/index/\nre_path(\'^app02/\', include((\'app02.urls\', \'app02\'))), # /app02/index\n\n# 这里的写法一定不要写错了,是include里面有一个元组,元组里面依此填内容\n# 第一个参数是app下面urls的地址,第二个参数就是app的别名(namespace)\n```\n\n后端如何取值?\n\n```python\ndef login(request):\n ...\n print(reverse(\'app01:login\'))\n # 有include的反向解析,需要加上别名,\n # 格式:namespace:name\n return ...\n```\n\n前端取值,和后端一样\n\n```html\n\n<form action=\"{% url \'app01:login\' %}\" method=\"post\">\n ...\n</form>\n```\n\n> 注意:有的时候编辑器会没有提示,不要怕,大胆写,你没有写错\n\n补充:\n\n如果在反向解析的时候,遇到的是含正则表达式的有分组匹配的\n\n需要为你的reverse多传一个参数\n\n```python\n# 无名分组用 args\nprint(reverse(\'login\', args=(12,)))\n# 你可以将匹配的内容放到这里\n# 有名分组用 kwargs\nprint(reverse(\'login\', kwargs={\'y\': 112}))\n```\n\n在前端中,也是这样进行操作\n\n不过不用区分无名分组与有名分组\n\n```html\n\n<form action=\"{% url \'login\' 12 %}\" method=\"post\">\n ...\n</form>\n```\n\n#### path方法\n\n之前我们讲到re_path的时候,在里面可以写正则表达式,进行匹配路径,特别的方便\n\n其实在我们的path中,也可以进行这样的操作\n\n```python\npath(\'login/<int:y>/\', views.login, name=\'login\'),\n```\n\n这里的`<int:y>`就是一种通用匹配方式\n\n> int 匹配数字\nstr 匹配除了路径分隔符之外的其他非空字符\nslug 匹配字母,数字,下划线,横杠\npath 匹配任何字符,包括路径分割符\n\n使用path中的通用匹配,就好比re_path中的有名分组\n\n将匹配的内容传递给`y`\n\n并且需要注意的是,int这个匹配规则,会将匹配上的数字,转换为int类型\n\n> 所以我们叫这个写法为 转换器\n\n#### 自定义转换器\n\n使用django自带的path方法中的匹配规则,有点不太够用,我们需要自定义转换器\n\n> 如何自定义转换器?\n\n1. 新建一个类\n2. 在类中编写代码,to_python,to_url方法必不可少\n3. 将这个类注册在转换器中\n\n```python\nfrom django.urls import path, register_converter\nfrom app01 import views\n\n\n# 自定义转换器\nclass MonConvert:\n # 自定义规则(正则表达式)\n regex = \'\\d\\d\'\n\n def to_python(self, value):\n # 这里的value就是匹配的值\n # 可以在这里对匹配的值进行一个操作\n return int(value)\n\n # 反向解析\n def to_url(self, value):\n return value\n\n\n# 注册转换器 类,转换器名称\nregister_converter(MonConvert, \'yyy\')\n\nurlpatterns = [\n path(\'login/<yyy:y>/\', views.login, name=\'login\'),\n]\n\n# <转换器名称:关键字参数名称>\n```\n\n编写好之后,最好是将这个类放入到一个公共的地方\n\n例如我放在`app01`下的`converter.py`中\n\n我需要在`app01`下的`__init__.py`中注册这个模块\n\n```python\n# init.py\nfrom app01 import converter\n```\n\n如果需要编写多个自定义转换器,只需要写多个类即可\n\n#### 请求对象与响应对象\n\n请求对象\n\n> 获取请求路径 `request.path`\n请求方式 `request.method`\n请求的参数 `request.GET` get请求参数\n请求的主机 `request.get`_host()\n\n响应对象\n\n> 三剑客','2022-01-12 11:16:22.117058','2022-03-10 22:50:05.203965',1,1,31,0,2,0,2,'枫枫','枫枫知道个人博客',8,NULL,NULL,3077),(29,'python基础--什么是数据类型','什么是数据类型\n简单的理解,存储数据的容器\n数据类型是每种编程语言必备属性,只有给数据赋予明确的数据类型,计算机才能对数据进行处理运算,因此,正确使用数据类型是十分必要的,不同的语','#### 什么是数据类型\n\n简单的理解,存储数据的容器\n\n> 数据类型是每种编程语言必备属性,只有给数据赋予明确的数据类型,计算机才能对数据进行处理运算,因此,正确使用数据类型是十分必要的,不同的语言,数据类型类似,但具体表示方法有所不同\n\n以下是Python编程常用的数据类型:\n\n- Number(数字)\n- String(字符串)\n- List(列表)\n- Tuple(元组)\n- Set(集合)\n- Dictionary(字典)\n\n不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组)\n\n可变数据 (3 个):List(列表)、Dictionary(字典)、Set(集合)\n\n可用 python 内置函数 type() 函数进行查看数据类型\n\n```python\nint_1 = 12\nprint(int_1, type(int_1))\nfloat_1 = 12.33\nprint(float_1, type(float_1))\ncomplex_1 = 2 + 7j\nprint(complex_1, type(complex_1))\nbool_1=True\nprint(bool_1,type(bool_1))\nstr_1=\'fengfeng\'\nprint(str_1,type(str_1))\nlist_1=[]\ntuple_1=()\ndict_1={}\nset_1=set() #空集合的创建有点特殊\nprint(list_1,type(list_1))\nprint(tuple_1,type(tuple_1))\nprint(dict_1,type(dict_1))\nprint(set_1,type(set_1))\n```\n\n> \n12.33 <class \'float\'>\n(2+7j) <class \'complex\'>\nTrue <class \'bool\'>\nfengfeng <class \'str\'>\n[] <class \'list\'>\n() <class \'tuple\'>\n{} <class \'dict\'>\nset() <class \'set\'>\n\n## 不可变数据(3 个):Number(数字)类型、String(字符串)、Tuple(元组)','2022-02-10 10:16:40.141325','2022-03-10 22:50:05.185949',1,1,2,0,0,0,2,'枫枫','枫枫知道个人博客',11,NULL,NULL,982),(4,'项目搭建','项目搭建\n搭建我们项目\n创建项目不要有中文!!!\n一定是专业版\n社区版是没有这个自动创建django项目的功能的!\n看到这个界面就可以成功运行了\n引入mysql\n```Python','## 项目搭建\n\n搭建我们项目\n\n创建项目不要有中文!!!\n\n![](http://python.fengfengzhidao.com/1031/20220102190211.png)\n\n一定是专业版\n\n社区版是没有这个自动创建django项目的功能的!\n\n![](http://python.fengfengzhidao.com/1031/20220102190426.png)\n\n看到这个界面就可以成功运行了\n\n引入mysql\n\n\n\n```Python\npip install pymysql\n\n```\n\n在app下面的init.py中\n\n```Python\nimport pymysql\n\npymysql.install_as_MySQLdb()\n\n```\n\n配置项\n\n```Python\n\nDATABASES = {\n \'default\': {\n \'ENGINE\': \'django.db.backends.mysql\',\n \'NAME\': \'zb_blog\', # 数据库名称\n \'USER\': \'root\', # 用户名\n \'PASSWORD\': \'root\', # 密码\n \'HOST\': \'127.0.0.1\', # 地址\n \'PORT\': 3306 # 端口\n }\n}\n```\n\nmysql创建数据库\n\n```Python\ncreate database v4_blog;\n```\n\n自己创建第三张表\n\n```Python\n# 自己创建第三张表\nAUTH_USER_MODEL = \"app01.UserInfo\"\n```\n\n数据库迁移\n\n```Python\npython manage.py makemigrations\npython manage.py migrate\n\n```\n\nscss的使用条件\n\n1. 安装node.js\n2. 安装scss\n3. 勾选配置\n\n ![](http://python.fengfengzhidao.com/1031/20220102192039.png)','2022-01-18 11:54:46.763151','2022-03-10 22:50:05.200963',1,1,234,0,46,5,1,'枫枫','枫枫知道个人博客',9,NULL,NULL,913),(27,'【项目相关】0207--分页器','课前准备知识\n获取所有的get请求参数\n```Python query_params = request.GET.copy()\n字典的格式\nprint(query_params)\n','## 课前准备知识\n\n获取所有的get请求参数\n\n```Python\nquery_params = request.GET.copy()\n# 字典的格式 <QueryDict: {\'id\': [\'1\'], \'aa\': [\'12\']}>\nprint(query_params)\n# 转换成url格式 id=1&aa=12\nprint(query_params.urlencode())\n```\n\n以后要做保留原搜索条件的\n\n\n\n```Python\nfrom urllib.parse import urlencode\nimport math\n\n\nclass Pagination:\n def __init__(self, current_page, all_count, base_url, query_params, per_page=20, pager_page_count=11):\n \"\"\"\n current_page 当前页码\n all_count 数据库中的总条数\n base_url 原始 URL\n query_params 保留原搜索条件\n per_page 一页展示多少条\n pager_page_count 最多显示多少个页码\n \"\"\"\n\n # 最多可以分多少页\n self.pager_count = math.ceil(all_count / per_page)\n\n # 当前页码可能是不符合要求的 数字区间\n try:\n self.current_page = int(current_page)\n if not 0 < self.current_page <= self.pager_count:\n self.current_page = 1\n except Exception:\n # 不符合条件的 就让它的页码变为 1\n self.current_page = 1\n\n self.base_url = base_url\n self.query_params = query_params\n self.per_page = per_page\n\n # 如果分页的数小于要显示的页码数\n self.pager_page_count = pager_page_count\n self.half_pager_page_count = int(self.pager_page_count / 2)\n if self.pager_count < self.pager_page_count:\n self.pager_page_count = self.pager_count\n\n # 每边的个数\n\n @property\n def start(self):\n return (self.current_page - 1) * self.per_page\n\n @property\n def end(self):\n return self.current_page * self.per_page\n\n # 生成 html页码\n def page_html(self):\n \"\"\"\n 计算页码的起始和结束 最多显示 11个 我当前的页码要在最中间\n 1 1 2 3 4 5 6 7 8 9 10 11\n 11 6 7 8 9 10 11 12 13 14 15 16\n :return:\n \"\"\"\n # 需要分类讨论\n\n # 正常情况\n start = self.current_page - self.half_pager_page_count + 1\n end = self.current_page + self.half_pager_page_count\n # 如果当前页码小于单边展示页码或者加上单边展示页码超出全部页码 那么就是特殊情况\n if self.current_page <= self.half_pager_page_count or self.current_page + self.half_pager_page_count >= self.pager_count:\n # 左边的特殊情况\n start = 1\n end = self.pager_page_count\n if self.current_page + self.half_pager_page_count >= self.pager_count:\n # 右边的特殊情况\n start = self.pager_count - self.pager_page_count + 1\n end = self.pager_count\n\n # 遍历\n page_list = []\n\n # 上一页\n if self.current_page == 1:\n # 如果是在第一页\n prev = f\'<li><a href=\"javascript: 0;\">上一页</a></li>\'\n else:\n self.query_params[\'page\'] = self.current_page - 1\n prev = f\'<li><a href=\"{self.base_url}?{self.query_encode}\">上一页</a></li>\'\n page_list.append(prev)\n\n for i in range(start, end + 1):\n self.query_params[\'page\'] = i\n # 生成标签\n # 如果是当前标签\n if self.current_page == i:\n li = f\'<li class=\"active\"><a href=\"{self.base_url}?{self.query_encode}\">{i}</a></li>\'\n else:\n li = f\'<li><a href=\"{self.base_url}?{self.query_encode}\">{i}</a></li>\'\n page_list.append(li)\n\n # 下一页\n if self.current_page == self.pager_count:\n # 如果是在第一页\n next = f\'<li><a href=\"javascript: 0;\">下一页</a></li>\'\n else:\n self.query_params[\'page\'] = self.current_page + 1\n next = f\'<li><a href=\"{self.base_url}?{self.query_encode}\">下一页</a></li>\'\n page_list.append(next)\n return \'\'.join(page_list)\n\n @property\n def query_encode(self):\n return urlencode(self.query_params)\n\n\nif __name__ == \'__main__\':\n pager = Pagination(\n current_page=1,\n all_count=4,\n base_url=\'/article\',\n query_params={\"tag\": \'python\'},\n per_page=1,\n )\n pager_str = pager.page_html()\n print(pager_str, pager.start, pager.end)\n\n```\n\n\n\n后端逻辑\n\n```Python\nclass Pagination:\n def __init__(self, current_page, all_count, base_url, query_params, per_page=20, pager_page_count=11,\n position=\'\'):\n \"\"\"\n 分页初始化\n :param current_page: 当前页码\n :param all_count: 数据库中总条数\n :param base_url: 基础URL\n :param query_params: QueryDict对象,内部含所有当前URL的原条件\n :param pager_page_count: 页面上最多显示的页码数量\n :param position: 页面上的定位点\n \"\"\"\n self.base_url = base_url\n self.query_params = query_params\n self.per_page = per_page\n self.all_count = all_count\n self.pager_page_count = pager_page_count\n pager_count, b = divmod(all_count, per_page) # 返回除数和余数\n if b != 0:\n pager_count += 1\n self.pager_count = pager_count\n\n half_pager_page_count = int(pager_page_count / 2)\n self.half_pager_page_count = half_pager_page_count\n\n self.position = position\n\n # 格式错误的页码或不在范围内的页面,设置为默认值1\n try:\n self.current_page = int(current_page)\n if not (0 < self.current_page <= self.pager_count):\n raise Exception()\n except Exception as e:\n self.current_page = 1\n\n @property\n def start(self):\n \"\"\"\n 数据获取值起始索引\n :return:\n \"\"\"\n return (self.current_page - 1) * self.per_page\n\n @property\n def end(self):\n \"\"\"\n 数据获取值结束索引\n :return:\n \"\"\"\n return self.current_page * self.per_page\n\n def page_html(self):\n \"\"\"\n 生成HTML页码\n :return:\n \"\"\"\n # 如果数据总页码pager_count<11 pager_page_count\n if self.pager_count < self.pager_page_count:\n pager_start = 1\n pager_end = self.pager_count\n else:\n # 数据页码已经超过11\n # 判断: 如果当前页 <= 5 half_pager_page_count\n if self.current_page <= self.half_pager_page_count:\n pager_start = 1\n pager_end = self.pager_page_count\n else:\n # 如果: 当前页+5 > 总页码\n if (self.current_page + self.half_pager_page_count) > self.pager_count:\n pager_end = self.pager_count\n pager_start = self.pager_count - self.pager_page_count + 1\n else:\n pager_start = self.current_page - self.half_pager_page_count\n pager_end = self.current_page + self.half_pager_page_count\n\n page_list = []\n\n if self.current_page <= 1:\n prev = \'<li><a href=\"javascript: 0;\">上一页</a></li>\'\n else:\n self.query_params[\'page\'] = self.current_page - 1\n prev = \'<li><a href=\"%s?%s#%s\">上一页</a></li>\' % (self.base_url, self.query_params.urlencode(), self.position)\n page_list.append(prev)\n\n for i in range(pager_start, pager_end + 1):\n self.query_params[\'page\'] = i\n if self.current_page == i:\n tpl = \'<li class=\"active\"><a href=\"%s?%s#%s\">%s</a></li>\' % (\n self.base_url, self.query_params.urlencode(), self.position, i,)\n else:\n tpl = \'<li><a href=\"%s?%s#%s\">%s</a></li>\' % (\n self.base_url, self.query_params.urlencode(), self.position, i,)\n page_list.append(tpl)\n\n if self.current_page >= self.pager_count:\n nex = \'<li><a href=\"javascript: 0;\">下一页</a></li>\'\n else:\n self.query_params[\'page\'] = self.current_page + 1\n nex = \'<li><a href=\"%s?%s#%s\">下一页</a></li>\' % (self.base_url, self.query_params.urlencode(), self.position)\n page_list.append(nex)\n\n page_str = \"\".join(page_list)\n return page_str\n\n```\n\n使用\n\n```Python\ndef index(request):\n all_article = Articles.objects.filter(status=1).order_by(\'-change_date\')\n\n from app01.utils.pagination import Pagination\n query_params = request.GET.copy()\n query_params._mutable = True\n\n pager = Pagination(\n current_page=request.GET.get(\'page\'), # 当前的页码\n all_count=all_article.count(), # 数据的总条数\n base_url=request.path_info, # 原路径\n per_page=2, # 一页显示的条数\n query_params=query_params, # 保留原搜索条件\n position=\'con\' # 定位点\n\n )\n article_list = all_article[pager.start:pager.end]\n\n return render(request, \'index.html\', locals())\n```\n\n\n\n前端部分\n\n```HTML\n<ul class=\"pager\">\n {{ pager.page_html|safe }}\n</ul>\n```\n\ncss\n\n```CSS\n .pager {\n width: 100%;\n list-style: none;\n display: flex;\n justify-content: center;\n \n > li {\n display: inline-flex;\n min-width: 30px;\n height: 30px;\n background-color: white;\n border-radius: 4px;\n justify-content: center;\n align-items: center;\n margin-right: 10px;\n padding: 0 10px;\n transition: all 0.3s;\n \n a[href=\"javascript: 0;\"] {\n cursor: not-allowed;\n }\n \n &:last-child {\n margin-right: 0;\n }\n \n &:hover {\n background-color: #f0eeee;\n }\n }\n \n > li.active {\n background-color: #ff9800;\n \n a {\n color: white;\n }\n }\n}\n```','2022-02-09 12:28:13.143023','2022-03-10 22:50:05.189954',1,1,18,0,1,1,2,'枫枫','枫枫知道个人博客',2,NULL,NULL,8949),(28,'python基础--异常处理','什么是异常?\n异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。\n一般情况下,在Python无法正常处理程序时就会发生一个异常。\n异常是Python对象,表示一','### 什么是异常?\n\n异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。\n\n一般情况下,在Python无法正常处理程序时就会发生一个异常。\n\n异常是Python对象,表示一个错误。\n\n当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。\n\npython提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。\n\n### python标准异常\n\n(红色的是最常见的python异常)\n\n|异常名称|描述|\n|-|-|\n|BaseException|所有异常的基类|\n|SystemExit|解释器请求退出|\n|KeyboardInterrupt|用户中断执行(通常是输入^C)|\n|Exception|常规错误的基类|\n|StopIteration|迭代器没有更多的值|\n|GeneratorExit|生成器(generator)发生异常来通知退出|\n|StandardError|所有的内建标准异常的基类|\n|ArithmeticError|所有数值计算错误的基类|\n|FloatingPointError|浮点计算错误|\n|OverflowError|数值运算超出最大限制|\n|ZeroDivisionError|除(或取模)零 (所有数据类型)|\n|AssertionError|断言语句失败|\n|AttributeError|对象没有这个属性|\n|EOFError|没有内建输入,到达EOF 标记|\n|EnvironmentError|操作系统错误的基类|\n|IOError|输入/输出操作失败|\n|OSError|操作系统错误|\n|WindowsError|系统调用失败|\n|ImportError|导入模块/对象失败|\n|LookupError|无效数据查询的基类|\n|IndexError|序列中没有此索引(index)|\n|KeyError|映射中没有这个键|\n|MemoryError|内存溢出错误(对于Python 解释器不是致命的)|\n|NameError|未声明/初始化对象 (没有属性)|\n|UnboundLocalError|访问未初始化的本地变量|\n|ReferenceError|弱引用(Weak reference)试图访问已经垃圾回收了的对象|\n|RuntimeError|一般的运行时错误|\n|NotImplementedError|尚未实现的方法|\n|SyntaxError|Python 语法错误|\n|IndentationError|缩进错误|\n|TabError|Tab 和空格混用|\n|SystemError|一般的解释器系统错误|\n|TypeError|对类型无效的操作|\n|ValueError|传入无效的参数|\n|UnicodeError|Unicode 相关的错误|\n|UnicodeDecodeError|Unicode 解码时的错误|\n|UnicodeEncodeError|Unicode 编码时错误|\n|UnicodeTranslateError|Unicode 转换时错误|\n|Warning|警告的基类|\n|DeprecationWarning|关于被弃用的特征的警告|\n|FutureWarning|关于构造将来语义会有改变的警告|\n|OverflowWarning|旧的关于自动提升为长整型(long)的警告|\n|PendingDeprecationWarning|关于特性将会被废弃的警告|\n|RuntimeWarning|可疑的运行时行为(runtime behavior)的警告|\n|SyntaxWarning|可疑的语法的警告|\n|UserWarning|用户代码生成的警告|\n\n\n### 异常处理\n\n捕捉异常可以使用`try/except`语句。\n\ntry/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。\n\n如果你不想在异常发生时结束你的程序,只需在try里捕获它。\n\n语法:\n\n```Python\ntry:\n 可能出异常的语句,用于捕获异常\nexcept 异常名称:\n 程序异常时所执行的语句,没有异常不执行该语句 \n```\n\ntry的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。\n\n> 如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。\n\n> 如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印默认的出错信息)。\n\n> 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。\n\n案例分析:捕获除法运算时被除数为0的异常\n\n```Python\nprint(4/0)\n# ZeroDivisionError: division by zero \n```\n\n我们可以看到被除数为0之后,程序直接就报了一个异常,那么我们就可以使用`try/except`语句进行捕获异常\n\n```Python\ntry:\n print(4/0)\nexcept ZeroDivisionError:\n print(\'被除数不能为0!\')\n# 被除数不能为0!\n```\n\n异常可以通过 try 语句来检测,任何在try语句块里的代码都会被监测, 检查有无异常发生。try 语句有两种主要形式: `try-except`和`try-finally `\n\n这两个语句是互斥的, 即只能使用其中的一种。一个try语句可以对应一个或多个except子句,但只能对应一个finally子句,或是一个try-except-finally复合语句\n\n可以使用`try-except`语句检测和处理异常,也可以添加一个可选的else子句处理没有探测到异常的时执行的代码,而try-finally只允许检测异常并做一些必要的清除工作(无论发生错误与否)\n\n### 使用except而不带任何异常类型\n\n你可以不带任何异常类型使用except,如下实例:\n\n```Python\ntry:\n 正常的操作\n ......................\nexcept:\n 发生异常,执行这块代码\n ......................\nelse:\n 如果没有异常执行这块代码\n```\n\n以上这个程序就是先执行try中的语句,如果发现异常就执行except中的代码,如果try中语句执行完类都没有异常就再去执行else中的语句\n\n以上方式try-except语句捕获所有发生的异常。但这不是一个很好的方式,我们不能通过该程序识别出具体的异常信息。因为它捕获所有的异常\n\n### 使用except而带多种异常类型\n\n你也可以使用相同的except语句来处理多个异常信息,如下所示:\n\n```Python\ntry:\n 正常的操作\n ......................\nexcept(Exception1,Exception2,......,ExceptionN):\n 发生以上多个异常中的一个,执行这块代码\n ......................\nelse:\n 如果没有异常执行这块代码\n```\n\n### try-finally 语句\n\ntry-finally 语句无论是否发生异常都将执行最后的代码\n\n```Python\ntry:\n <语句>\nfinally:\n <语句> #退出try时总会执行\n\n```\n\n当在try块中抛出一个异常,立即执行finally块代码。\n\nfinally块中的所有语句执行后,异常被再次触发,并执行except块代码。\n\n![](https://secure2.wostatic.cn/static/xgMgpvBoAYa1pb8rXh4mi9/image.png)\n\n```Python\ntry:\n find()\nexcept NameError as error:\n print(error)\nelse:\n try:\n with open(\'file.log\') as file:\n read_data = file.read()\n except FileNotFoundError as fnf_error:\n print(fnf_error)\nfinally:\n print(\'这句话,无论异常是否发生都会执行。\')\n```\n\n> name \'find\' is not defined\n这句话,无论异常是否发生都会执行。\n\n\n\n### 异常的参数\n\n一个异常可以带上参数,可作为输出的异常信息参数。\n\n你可以通过except语句来捕获异常的参数,如下所示:\n\n```Python\ntry:\n 正常的操作\n ......................\nexcept ExceptionType as Argument:\n 你可以在这输出 Argument 的值... \n```\n\n异常参数就是python中出现异常之后所给出的提示信息,如下异常\n\n```Python\nZeroDivisionError: division by zero \n```\n\ndivision by zero 就是异常的参数,我们可以使用`except ZeroDivisionError as error:`将它打印出来\n\n```Python\ntry:\n print(4/0)\nexcept ZeroDivisionError as error:\n print(f\'除数不能为0:{error}\')\n# 除数不能为0:division by zero\n```\n\n### 抛出异常\n\nPython 使用 raise 语句抛出一个指定的异常。\n\nraise语法格式如下:\n\n```Python\nraise Exception (输出的参数)\n```\n\n例如:如果 x 大于 5 就触发异常\n\n```Python\nx = 10\nif x > 5:\n raise Exception(\'x 不能大于 5。x 的值为: {}\'.format(x))\n# Exception: x 不能大于 5。x 的值为: 10 \n```\n\nraise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类),Exception是自己指定一个错误名称,而异常参数是()中的字符串内容\n\n如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出\n\n```Python\ntry:\n raise NameError(\'HiThere\')\nexcept NameError:\n print(\'An exception flew by!\')\n raise\n```\n\n如果没有raise语句,那么程序就只打印`An exception flew by!`,那么加上raise语句,程序就出现异常,异常信息就是`NameError: HiThere`','2022-02-09 12:29:18.518356','2022-03-10 22:50:05.187952',1,1,13,0,1,0,2,'枫枫','枫枫知道个人博客',5,NULL,NULL,4827),(7,'优化后端代码','优化后端代码\n之前\n```Python from django.views import View from django.http import JsonResponse fro','优化后端代码\n\n之前\n\n```Python\nfrom django.views import View\nfrom django.http import JsonResponse\nfrom markdown import markdown\nfrom pyquery import PyQuery\nfrom app01.models import Tags, Articles, Cover\n\n\n# 文章\nclass ArticleView(View):\n # 发布文章\n def post(self, request):\n res = {\n \'msg\': \'文章发布成功!\',\n \'code\': 412,\n \"data\": None\n }\n\n data: dict = request.data\n print(data)\n title = data.get(\'title\')\n if not title:\n res[\'msg\'] = \'请输入文章标题\'\n return JsonResponse(res)\n\n content = data.get(\'content\')\n recommend = data.get(\'recommend\')\n if not content:\n res[\'msg\'] = \'请输入文章内容\'\n return JsonResponse(res)\n extra = {\n \'title\': title,\n \'content\': content,\n \'recommend\': recommend,\n \'status\': 1,\n }\n # 解析文本内容\n abstract = data.get(\'abstract\')\n if not abstract:\n abstract = PyQuery(markdown(content)).text()[:30]\n extra[\'abstract\'] = abstract\n\n category = data.get(\'category_id\')\n if category:\n extra[\'category\'] = category\n\n cover_id = data.get(\'cover_id\')\n if cover_id:\n extra[\'cover_id\'] = cover_id\n else:\n extra[\'cover_id\'] = 1\n\n pwd = data.get(\'pwd\')\n if pwd:\n extra[\'pwd\'] = pwd\n\n # 添加文章\n article_obj = Articles.objects.create(**extra)\n # 标签\n tags = data.get(\'tags\')\n if tags:\n for tag in tags:\n if not tag.isdigit():\n tag_obj = Tags.objects.create(title=tag)\n article_obj.tag.add(tag_obj)\n else:\n article_obj.tag.add(tag)\n\n res[\'code\'] = 0\n res[\'data\'] = article_obj.nid\n return JsonResponse(res)\n```\n\n\n\n之后\n\n```Python\nclass AddArticleForm(forms.Form):\n title = forms.CharField(error_messages={\'required\': \'请输入文章标题\'})\n content = forms.CharField(error_messages={\'required\': \'请输入文章内容\'})\n cover_id = forms.IntegerField(required=False)\n category = forms.IntegerField(required=False)\n status = forms.IntegerField(required=False)\n recommend = forms.BooleanField(required=False)\n pwd = forms.CharField(required=False)\n abstract = forms.CharField(required=False)\n\n # 全局钩子\n def clean(self):\n category = self.cleaned_data[\'category\']\n if not category:\n self.cleaned_data.pop(\'category\')\n\n pwd = self.cleaned_data[\'pwd\']\n if not pwd:\n self.cleaned_data.pop(\'pwd\')\n return self.cleaned_data\n\n # 文章简介\n def clean_abstract(self):\n abstract = self.cleaned_data[\'abstract\']\n if not abstract:\n content = self.cleaned_data.get(\'content\')\n if not content:\n return\n abstract = PyQuery(markdown(content)).text()[:30]\n return abstract\n\n # 文章封面\n def clean_cover_id(self):\n cover_id = self.cleaned_data[\'cover_id\']\n if not cover_id:\n # 随机选择一个\n cover_list = Cover.objects.all().values(\'nid\')\n cover_id = random.choice(cover_list)[\'nid\']\n return cover_id\n\n\nclass ArticleView(View):\n # 发布文章\n def post(self, request):\n res = {\n \'msg\': \'文章发布成功!\',\n \'code\': 412,\n \"data\": None\n }\n data = request.data\n data[\'status\'] = 1\n form = AddArticleForm(data)\n if not form.is_valid():\n # 验证不通过\n res[\'self\'], res[\'msg\'] = clean_form(form)\n return JsonResponse(res)\n # 添加文章\n article_obj = Articles.objects.create(**form.cleaned_data)\n # 标签\n tags = data[\'tags\']\n for tag in tags:\n if not tag.isdigit():\n tag_obj = Tags.objects.create(title=tag)\n article_obj.tag.add(tag_obj)\n else:\n article_obj.tag.add(tag)\n res[\'code\'] = 0\n res[\'data\'] = article_obj.nid\n return JsonResponse(res)\n```','2022-01-20 11:45:03.174633','2022-03-10 22:50:05.196959',1,1,9,0,0,2,2,'枫枫','枫枫知道个人博客',7,NULL,NULL,4071),(30,'python基础--条件语句','if语法\nPython条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。\n可以通过下图来简单了解条件语句的执行过程:\nPython程序语言指定任何','#### if语法\n\nPython条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。\n\n可以通过下图来简单了解条件语句的执行过程:\n\n![](https://secure2.wostatic.cn/static/cgftHjFUdHRRCCpXB8bS4W/image.png)\n\nPython程序语言指定任何非0和非空(null)值为true,0 或者 null为false。\n\nPython 编程中 if 语句用于控制程序的执行,基本形式为:\n\n```Python\nif 判断条件:\n 语句1……\nelse:\n 语句2……\n```\n\n语句1就是if判断条件成立所执行的语句\n\n那么判断条件不成立,就执行else下的语句2\n\n在python中,使用缩进来表示层级关系\n\n```Python\nif 5>2:\n print(\"条件成立\",\"执行语句1\")\nelse:\n print(\'条件不成立\',\"执行语句2\")\n# 条件成立 执行语句1 \n```\n\nif 语句的判断条件可以用>(大于)、<(小于)、==(等于)、>=(大于等于)、<=(小于等于)来表示其关系。\n\n当判断条件为多个值时,可以使用以下形式:\n\n```Python\nif 判断条件1:\n 执行语句1……\nelif 判断条件2:\n 执行语句2……\nelif 判断条件3:\n 执行语句3……\nelse:\n 执行语句4……\n```\n\n如下例:\n\n```Python\n# 根据分数判断等级\nscore = int(input(\"请输入你的成绩:\"))\nif score >=60 and score <80:\n print(\"成绩及格\")\nelif score>=80 and score <90:\n print(\"成绩良好\")\nelif score>=90 and score <=100:\n print(\"成绩优秀\")\nelse:\n print(\"成绩不及格\")\n \n# 输入 50 输出成绩不及格\n# 输入 88 输出成绩良好\n```\n\n由于 python 并不支持 switch 语句,所以多个条件判断,只能用 elif 来实现,如果判断需要多个条件需同时判断时,可以\n\n1. 使用 or (或),表示两个条件有一个成立时判断条件成功\n2. 使用 and (与)时,表示只有两个条件同时成立的情况下,判断条件才成功。\n\n当if有多个条件时可使用括号来区分判断的先后顺序,括号中的判断优先执行\n\n此外 and 和 or 的优先级低于>(大于)、<(小于)等判断符号,即大于和小于在没有括号的情况下会比与或要优先判断\n\n---\n\n你也可以在同一行的位置上使用if条件判断语句和输出语句,如下:\n\n```Python\n# 根据分数判断等级\nscore = int(input(\"请输入你的成绩:\"))\nif score >=60 and score <80: print(\"成绩及格\")\nelif score>=80 and score <90: print(\"成绩良好\")\nelif score>=90 and score <=100: print(\"成绩优秀\")\nelse: print(\"成绩不及格\")\n \n# 输入 50 输出成绩不及格\n# 输入 88 输出成绩良好\n```\n\n\n\n### if嵌套\n\n[Python](http://c.biancheng.net/python/) 中,if、if else 和 if elif else 之间可以相互嵌套。因此,在开发程序时,需要根据场景需要,选择合适的嵌套方案。需要注意的是,在相互嵌套时,一定要严格遵守不同级别代码块的缩进规范。\n\n例如,在最简单的 if 语句中嵌套 if else 语句,形式如下:\n\n```Python\nif 表达式 1:\n if 表示式 2:\n 代码块 1\n else:\n 代码块 2\n```\n\n又或者,在 if else 语句中嵌套 if else 语句,形式如下:\n\n```Python\nif 表示式 1:\n if 表达式 2:\n 代码块 1\n else:\n 代码块 2\nelse:\n if 表达式 3:\n 代码块 3\n else:\n 代码块 4\n```\n\n【实例】判断是否为酒后驾车 \n如果规定,车辆驾驶员的血液酒精含量小于 20mg/100ml 不构成酒驾;酒精含量大于或等于 20mg/100ml 为酒驾;酒精含量大于或等于 80mg/100ml 为醉驾。先编写 Python 程序判断是否为酒后驾车。\n\n![](https://secure2.wostatic.cn/static/rr7YogJgXdUUAxz6V5N35B/image.png)\n\n于是我们使用if嵌套来实现这个需求:\n\n```Python\nproof = int(input(\"输入驾驶员每 100ml 血液酒精的含量:\"))\nif proof < 20:\n print(\"驾驶员不构成酒驾\")\nelse:\n if proof < 80:\n print(\"驾驶员已构成酒驾\")\n else:\n print(\"驾驶员已构成醉驾\")\n```\n\n又或者使用if嵌套改进我们的得分评判系统:\n\n```Python\nscore = int(input(\"请输入你的成绩:\"))\nif score >= 60:\n if score>=80:\n if score>=90:\n print(\"成绩优秀\")\n else:\n print(\"成绩良好\")\n else:\n print(\"成绩及格\")\nelse:\n print(\"成绩不及格\")\n# 这次我们实现的是三重嵌套 \n```\n\n\n\n### 三目运算\n\nPython 可通过 if 语句来实现三目运算符的功能,因此可以近似地把这种 if 语句当成三目运算符。作为三目运算符的 if 语句的语法格式如下:\n\n```Python\nTrue_code if decide else False_code\n```\n\n三目运算符的规则是:先对逻辑表达式 expression 求值,如果逻辑表达式返回 True,则执行并返回 True_statements 的值;如果逻辑表达式返回 False,则执行并返回 False_statements 的值\n\n```Python\n条件成立执行语句1 if 条件 else 条件不成立执行语句2\n```\n\n看如下代码:\n\n```Python\na = 5\nb = 3\nst = \"a大于b\" if a > b else \"a不大于b\"\n# 输出\"a大于b\"\nprint(st)\n```\n\n如果只是需要在控制台看到结果,那我们可以这样写:\n\n```Python\na,b=3,5\nprint(f\"{a}>{b}\") if a>b else print(f\"{a}<{b}\")\n# 3<5\n```\n\n又或者是使用一个print语句\n\n```Python\na,b=5,3\nprint(f\"{a}>{b}\" if a>b else f\"{a}<{b}\")\n```\n\n实例:使用三目运算符实现判断两个数字大小(实现if else 语句的效果)\n\n```Python\nx=int(input(\'请输入第一个数字\'))\ny=int(input(\'请输入第二个数字\'))\nif x>y:\n print(f\'{x}大于{y}\')\nelse:\n print(f\'{x}小于{y}\')\n\n```\n\n```Python\n# 条件成立那里放前面,else语句下面就放后面\nx=int(input(\'请输入第一个数字\'))\ny=int(input(\'请输入第二个数字\'))\nprint(f\'{x}大于{y}\' if x>y else f\'{x}小于{y}\') \n```\n\n我们同样可以使用如if嵌套的方法进行三目运算符嵌套,这样可以构成更加复杂的表达式。在嵌套时需要注意 if 和 else 的配对,例如:\n\n```Python\na if a>b else c if c>d else d\n# 理解为\na if a>b else ( c if c>d else d ) \n# 可以使用小括号\n\n```\n\n这是使用if else 在三个数字中输出最小的数\n\n```Python\na, b, c = -1, -5, 1\nif a < b and a < c:\n print(a)\nelif b < c and b < a:\n print(b)\nelse:\n print(c)\n```\n\n如何用三目运算符进行实现?课后作业!\n\n```Python\na, b, c = -1, 2, 1\nprint(a if a < b and a < c else b if b < c and b < a else c)\n\n```','2022-02-10 10:17:13.283442','2022-03-10 22:50:05.184948',1,1,1,0,0,0,2,'枫枫','枫枫知道个人博客',3,NULL,NULL,3840),(31,'python基础--循环语句','在流程控制中,难免会有一些重复的工作,比如给100个变量复制,打印列表中的每一个元素等,如果都每一条语句都要我们自己进行操作,那工作量是非常大的\n在python中,有两个循环语句,','在流程控制中,难免会有一些重复的工作,比如给100个变量复制,打印列表中的每一个元素等,如果都每一条语句都要我们自己进行操作,那工作量是非常大的\n\n在python中,有两个循环语句,`while`和`for` ,两个的原理类似,先判断条件,条件成立就执行循环体内的语句,然后再次判断条件是否成立,再次执行循环内的语句,直到条件不成立\n\n### while循环\n\n#### 语法\n\nPython 编程中 while 语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务。其基本形式为:\n\n```Python\nwhile 条件满足:\n 语句1...\nelse:\n 循环完成后 要执行的语句\n```\n\n执行语句可以是单个语句或语句块。判断条件可以是任何表达式,任何非零、或非空(null)的值均为true\n\n当判断条件为假(False)时,循环结束\n\n### 死循环\n\n当条件一直为真时会一直循环下去,一直在循环内,不能走出循环的语句,被称为“死循环”又叫“无限循环”\n\n```Python\n# 最简单的死循环语句\nwhile True:\n print(\'这是一条死循环\')\n```\n\n### 循环使用 else 语句\n\n在 python 中,while … else 在循环条件为 false 时执行 else 语句块:\n\n```Python\ncount = 0\nwhile count < 5:\n print (count, \" is less than 5\")\n count = count + 1\nelse:\n print (count, \" is not less than 5\") \n```\n\n条件成立时,执行第一个print语句,然后count+1,直到count加到5,条件不满足,执行else下的print语句\n\n可用于判断循环结构是否结束\n\n### 简单语句组\n\n类似 if 语句的语法,如果你的 while 循环体中只有一条语句,你可以将该语句与while写在同一行中, 如下所示:\n\n```Python\nflag = 1\nwhile (flag): print \'Given flag is really true!\'\nprint \"Good bye!\"\n```\n\n使用while循环计算1+2+......+99+100的值:\n\n```Python\ni=1\nsum=0\nwhile i<=100:\n sum+=i\n i+=1\nprint(sum)\n# 5050 \n```\n\n### for循环\n\n它常用于遍历字符串、列表、元组、字典、集合等序列类型,逐个获取序列中的各个元素\n\nfor 循环的语法格式如下:\n\n```Python\nfor 迭代变量 in 字符串|列表|元组|字典|集合:\n 代码块\n```\n\n格式中,迭代变量用于存放从序列类型变量中读取出来的元素,所以一般不会在循环中对迭代变量手动赋值\n\n代码块指的是具有相同缩进格式的多行代码(和 while 一样),由于和循环结构联用,因此代码块又称为循环体\n\n```Python\nadd = \"https://www.baidu.com\"\n#for循环,遍历 add 字符串\nfor ch in add:\n print(ch,end=\"\")\n# 输出:https://www.baidu.com\n```\n\n可以看到,使用 for 循环遍历 add 字符串的过程中,迭代变量 ch 会先后被赋值为 add 字符串中的每个字符,并代入循环体中使用。只不过例子中的循环体比较简单,只有一行输出语句\n\n实现计算1+2+......+99+100的值\n\n```Python\nprint(\"计算 1+2+...+100 的结果为:\")\n#保存累加结果的变量\nresult = 0\n#逐个获取从 1 到 100 这些值,并做累加操作\nfor i in range(101):\n result += i\nprint(result)\n# 计算 1+2+...+100 的结果为:\n# 5050 \n```\n\n这个时候,在我们的代码里面出现了一个陌生的函数——range( )函数\n\n### range( ) 的使用\n\n上面代码中,使用了 range() 函数,此函数是 Python 内置函数,用于生成一系列连续整数,多用于 for 循环中\n\n我们这里只需要明白range() 函数可以进行数字迭代生成就好了\n\n### for循环遍历列表和元组\n\n当用 for 循环遍历 list 列表或者 tuple 元组时,其迭代变量会先后被赋值为列表或元组中的每个元素并执行一次循环体\n\n```Python\n# 对列表进行遍历\nmy_list = [1,2,3,4,5]\nfor ele in my_list:\n print(\'ele =\', ele) \n \n```\n\n> ele = 1\nele = 2\nele = 3\nele = 4\nele = 5\n\n```Python\n# 对元组进行遍历\nmy_list = (1,2,3,4,5)\nfor ele in my_list:\n print(\'ele =\', ele)\n \n```\n\n可以看到两者结果是完全相同的\n\n> ele = 1\nele = 2\nele = 3\nele = 4\nele = 5\n\n\n\n### for 循环遍历字典\n\n在使用 for 循环遍历字典时,经常会用到和字典相关的 3 个方法,即 items()、keys() 以及 values(),它们各自的用法已经在前面章节中讲过,这里不再赘述。当然,如果使用 for 循环直接遍历字典,则迭代变量会被先后赋值为每个键值对中的键。\n\n```Python\ndic={\'name\':\'小明\',\'age\':22,\'score\':100}\nfor di in dic:\n print(di)\n# 得到字典的每一个键(key)默认\nfor di in dic.items():\n print(di)\n# 得到字典的每一组数据,其结果为一个元组\nfor di in dic.values():\n print(di)\n# 得到字典的每一组键所对应的值 \nfor di in dic.keys():\n print(di)\n#得到字典的每一键(key) 默认情况\n```\n\n字典中的items( )、keys( ) 以及 values ( ) 的用法\n\nitems():以列表返回可遍历的(键, 值) 元组数组\n\nitems() 方法的遍历:items() 方法把字典中每对 key 和 value 组成一个元组,并把这些元组放在列表中返回\n\n```Python\nd = {\'one\': 1, \'two\': 2, \'three\': 3}\n>>> d.items()\ndict_items([(\'one\', 1), (\'two\', 2), (\'three\', 3)])\n>>> type(d.items())\n<class \'dict_items\'>\n\n>>> for key,value in d.items():#当两个参数时\n print(key + \':\' + str(value))\none:1\ntwo:2\nthree:3\n\n>>> for i in d.items():#当参数只有一个时\n print(i)\n(\'one\', 1)\n(\'two\', 2)\n(\'three\', 3)\n```\n\nkeys():以列表返回一个字典所有的键\n\nvalues():以列表返回一个字典所有的值\n\n### for练习\n\n- 求1~100内偶数之和\n\n```Python\nsum = 0\nfor i in range(2,101,2):\n sum += i\nprint(sum)\n```\n\n- 求阶乘\n\n```Python\n# 求阶乘\nnum = int(input(\'请输入一个数字:\'))\nres = 1\nfor i in range(1, num + 1): \n res*=i\nprint(\'%d的阶乘为:%d\' %(num,res))\n```\n\n- 9*9乘法表\n\n```Python\nfor i in range(1,10):\n for j in range(1,i+1):\n print(\'%d * %d = %d\\t\' %(i,j,i*j),end=\'\')\n print()\n```\n\n- 求最大公约数和最小公倍数\n\n```Python\n# 输入两个数字\nnum1=int(input(\'Num1:\'))\nnum2=int(input(\'Num2:\')) \n# 找出两个数中的较小者\nmin_num = min(num1,num2) \n# 确定最大公约数\nfor i in range(1,min_num+1): \n if num1 % i ==0 and num2 % i ==0: \n max_commer = i\n# 求最小公倍数\nmin_commer =int(num1 * num2)/max_commer \nprint(\'%s 和 %s 的最大公约数为%s\' %(num1,num2,max_commer))\nprint(\'%s 和 %s 的最小公倍数为%s\' %(num1,num2,min_commer))\n```\n\n\n\n### break的使用\n\nPython break语句,就像在C语言中,打破了最小封闭for或while循环。\n\nbreak语句用来终止循环语句,即循环条件没有False条件或者序列还没被完全递归完,也会停止执行循环语句。\n\nbreak语句用在`while`和`for`循环中。\n\n如果您使用嵌套循环,break语句将停止执行最深层的循环,并开始执行下一行代码。\n\n---\n\n我们知道,在执行 while 循环或者 for 循环时,只要循环条件满足,程序将会一直执行循环体,不停地转圈。但在某些场景,我们可能希望在循环结束前就手动离开循环,Pyhton 提供了 2 种强制离开当前循环体的办法:\n\n1. 使用 continue 语句,可以跳过执行本次循环体中剩余的代码,转而执行下一次的循环。\n2. 只用 break 语句,可以完全终止当前循环。\n\n我们先来了解`break`语句\n\n在某些场景中,如果需要在某种条件出现时强行中止循环,而不是等到循环条件为 False 时才退出循环,就可以使用 break 来完成这个功能。\n\nbreak 用于完全结束一个循环,跳出循环体。不管是哪种循环,一旦在循环体中遇到 break,系统就将完全结束该循环,开始执行循环之后的代码。\n\n\n\n这就好比在操场上跑步,原计划跑 10 圈,可是当跑到第 2 圈的时候,突然想起有急事要办,于是果断停止跑步并离开操场,这就相当于使用了 break 语句提前终止了循环。\n\nbreak 语句一般会结合 if 语句进行搭配使用,表示在某种条件下,跳出循环体,如果使用嵌套循环,break 语句将跳出当前的循环体。\n\nbreak 语句的语法非常简单,只需要在相应 while 或 for 语句中直接加入即可。例如如下程序:\n\n```Python\n# 一个简单的for循环\nfor i in range(0, 10) :\n print(\"i的值是: \", i)\n if i == 2 :\n # 执行该语句时将结束循环\n break\n```\n\n当i等于2时系统结束循环\n\nbreak 语句导致了 i==2 时执行结束,因为当 i==2 时,在循环体内遇到了 break 语句,程序跳出该循环。 \n\n需要注意的是,对于带 else 块的 for 循环,如果使用 break 强行中止循环,程序将不会执行 else 块。例如如下程序:\n\n```Python\n# 一个简单的for循环\nfor i in range(0, 10) :\n print(\"i的值是: \", i)\n if i == 2 :\n # 执行该语句时将结束循环\n break\nelse:\n print(\'else块: \', i) # 这个else语句并不会执行\n```\n\n上面程序同样会在 i==2 时跳出循环,而且此时 for 循环不会执行 else 块。\n\n在使用 break 语句的情况下,循环的 else 代码块与直接放在循环体后是有区别的,即如果将代码块放在 else 块中,当程序使用 break 中止循环时,循环不会执行 else 块;如果将代码块直接放在循环体后面,当程序使用 break 中止循环时,程序自然会执行循环体之后的代码块。\n\n另外,针对嵌套的循环结构来说,Python 的 break 语句只能结束其所在的循环体,而无法结束嵌套所在循环的外层循环。例如:\n\n```Python\nfor i in range(0,4) :\n print(\"此时 i 的值为:\",i)\n for j in range(5):\n print(\" 此时 j 的值为:\",j)\n break\n print(\"跳出内层循环\")\n```\n\n分析运行结果不难看出,每次执行内层循环体时,第一次循环就会遇到 break 语句,即做跳出所在循环体的操作,转而执行外层循环体的代码。\n\n如果想达到 break 语句不仅跳出单前所在循环,同时跳出外层循环的目的,可先定义 bool 类型的变量来标志是否需要跳出外层循环,然后在内层循环、外层循环中分别使用两条 break 语句来实现。例如如下程序:\n\n```Python\nexit_flag = False\n# 外层循环\nfor i in range(0, 5) :\n # 内层循环\n for j in range(0, 3 ) :\n print(\"i的值为: %d, j的值为: %d\" % (i, j))\n if j == 1 :\n exit_flag = True\n # 跳出里层循环\n break\n # 如果exit_flag为True,跳出外层循环\n if exit_flag :\n break \n\n```\n\n上面程序在内层循环中判断 j 是否等于 i,当 j 等于 i 时,程序将 exit_flag 设为 True,并跳出内层循环;接下来程序开始执行外层循环的剩下语句,由于 exit_flag 为 True,因此也会执行外层循环的 break 语句来跳出外层循环。\n\n程序从外层循环进入内层循环后,当 j 等于 i 时,程序将 exit_flag 设为 True,并跳出内层循环;接下来程序又执行外层循环的 break 语句,从而跳出外层循环。\n\n### continue的使用\n\n和 break 语句相比,continue 语句的作用则没有那么强大,它只会终止执行本次循环中剩下的代码,直接从下一次循环继续执行。\n仍然以在操作跑步为例,原计划跑 10 圈,但当跑到 2 圈半的时候突然接到一个电话,此时停止了跑步,当挂断电话后,并没有继续跑剩下的半圈,而是直接从第 3 圈开始跑。\ncontinue 语句的用法和 break 语句一样,只要 while 或 for 语句中的相应位置加入即可。例如:\n\n```Python\nadd = \"https://baidu.com,https://zhihu.com\"\n# 一个简单的for循环\nfor i in add:\n if i == \',\' :\n # 忽略本次循环的剩下语句\n print(\'\\n\')\n continue\n print(i,end=\"\")\n# https://baidu.com\nhttps://zhihu.com\n```\n\n程序在遇到 \' ,\' 时,跳过本次循环,进行下一次循环\n\n#### continue的作用\n\n结合异常处理(try),查找异常报告并跳过这次异常\n\n\n\n### range使用\n\nrange语法\n\n```Python\nrange(start,stop,step)\n```\n\n> start:开始\nstop:结束(stop值是不包含的)\nstep:步长\n\npython2.x range() 函数可创建一个整数列表,一般用在 for 循环中\n\n注意:Python3 range() 返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表,具体可查阅 [Python3 range()](https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=range#range) 用法说明。\n`print(range(1,100),type(range(1,100)))`\n`# range(1, 100) <class \'range\'>`\n我们可用使用list函数返回列表\n\n```Python\nprint(list(range(1,10)))\n# [1, 2, 3, 4, 5, 6, 7, 8, 9] \n```\n\n一些range对象的例子\n\n> list(range(10))\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\nlist(range(1, 11))\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n list(range(0, 30, 5))\n[0, 5, 10, 15, 20, 25]\n list(range(0, 10, 3))\n[0, 3, 6, 9]\n list(range(0, -10, -1))\n[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n list(range(0))\n[] \nlist(range(1, 0))\n[]\n\nrange 对象实现了 一般 序列的所有操作,但拼接和重复除外(这是由于 range 对象只能表示符合严格模式的序列,而重复和拼接通常都会违反这样的模式)\n\n[`range`](https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=range#range) 类型相比常规 [`list`](https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=range#list) 或 [`tuple`](https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=range#tuple) 的优势在于一个 [`range`](https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=range#range) 对象总是占用固定数量的(较小)内存,不论其所表示的范围有多大(因为它只保存了 `start`, `stop` 和 `step` 值,并会根据需要计算具体单项或子范围的值)\n\nrange 对象实现了 collections.abc.Sequence ABC,提供如包含检测、元素索引查找、切片等特性,并支持负索引\n\n```Python\nr = range(0, 20, 2)\n# 0 2 4 6 8 10 12 14 16 18 \n```\n\n```\n>> r\nrange(0, 20, 2)\n>> 11 in r #包含检测\nFalse\n>> 10 in r\nTrue\n>> r.index(10) # 根据内容查索引值\n5\n>> r[5] # 根据索引查内容值\n10\n>> r[:5] # 切片返回类一个新的range对象\nrange(0, 10, 2)\n>> r[-1] # 取最后一个元素,是在range(0,20,2)上面进行的\n18\n```\n\n[while循环](https://www.wolai.com/jAADGpGH99vaQjNkA15fzF)','2022-02-10 10:18:08.681790','2022-03-10 22:50:05.182947',1,1,3,0,0,0,2,'枫枫','枫枫知道个人博客',19,NULL,NULL,8505),(32,'枫枫知道--Vue全系列课程','vue基本概述\nVue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。\nVue.js是一套构建用户界面的渐进式框架,采用自底向上增量开发的设计。Vu','# vue基本概述\n\nVue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。\n\nVue.js是一套构建用户界面的渐进式框架,采用自底向上增量开发的设计。Vue的核心库关注于视图(html),不仅易上手,还便于与第三方库或项目整合。\n\n渐进式:一步一步,不是将所有的东西都学完才能使用。\n\n自底向上设计:一种设计程序的过程和方法,就是先编写出基础程序段,然后在逐步扩大规范、补充和升级某些 功能,实际上是一种自底向上构造程序的过程。\n\nVue.js的核心是允许采用简洁式模板语法来声明的将数据渲染进DOM的系统\n\n在使用数据之前需要先进性声明才可以使用\n\n### 为什么要学习Vue?\n\n简单,前端三大框架(Vue,React,angler)中是对小白最友好的框架\n\n另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。\n\n### Vue和Jquery有什么区别?\n\n数据驱动试图\n\n1. jquery到vue转变是一个思想的转变,是将jquery直接操作dom的思想转变到操作数据上去。\n2. jQuery是使用选择器选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象\n3. Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM\n\n### 什么时候学习Vue?\n\n先把前端三件套熟悉(HTML,CSS,JavaScript)\n\n\n\n\n\n# Vue基本语法\n\n官方文档\n\n\n\n## 插值表达式\n\n使用{{ }}进行渲染`data:{}`里面的变量\n\n也可以是函数,不过在data里面的方法,在插值表达式中需要补充大括号\n\n例如\n\n```HTML\n<div id=\"app\">\n <div>{{ msg }}</div>\n <div>{{ getInfo() }}</div>\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n new Vue({\n el: \'#app\',\n data: {\n msg: \'枫枫知道\',\n getInfo() {\n // 函数的返回值就是插值表达式中的结果\n return \"床前明月光\"\n }\n }\n })\n</script>\n```\n\n\n\n![](http://python.fengfengzhidao.icu/img/20211208164829.png)\n\n在插值表达式中,支持运算符,以及一些方法\n\nvue指令:\n\n## v-text\n\n渲染文本,和插值表达式类似\n\n```HTML\n<div v-text=\"msg\"></div>\n<div>{{ msg }}</div>\n```\n\n也是支持运算符的\n\n```HTML\n<div v-text=\"2 > 4 ? \'成立\': \'不成立\'\"></div>\n```\n\n## v-html\n\n渲染标签,如果字符串是含标签的特殊字符,那么vue会将它渲染成标签\n\n如果是v-text或者是使用插值表达式,则会原样输出\n\n![](http://python.fengfengzhidao.icu/img/20211208165756.png)\n\n注意:\n\nv-html一般是用来渲染信任的文本,例如文章的详情内容等,最好不要用在用户提交的地方\n\n容易造成XSS攻击\n\n## v-bind\n\n可以给标签动态添加内容,也可以给动态的修改标签属性\n\n不过在属性上的操作稍微和操作内容不太一样,我们使用`v-bind`指令\n\n例如我想动态修改img标签的src属性,希望它去读取data里面的值\n\n但是我们不能在属性中使用插值表达式\n\n![](http://python.fengfengzhidao.icu/img/20211208170933.png)\n\n这样写src直接将我的内容原样输出了,所以我们需要使用v-bind,全称为动态属性\n\n那么我可以这么做\n\n```HTML\n<img v-bind:src=\"src\" alt=\"\">\n```\n\n![](http://python.fengfengzhidao.icu/img/20211208171135.png)\n\n当然,`v-bind:` 可以简写为 `:`\n\n```HTML\n<img :src=\"src\" alt=\"\">\n\n```\n\nv-bind不仅可以用于HTML存在的属性,还可以应用在自定义属性上\n\n例如\n\n```HTML\n<p :id=\"\'p\' + \'_01\'\" :data=\"msg\" :还可以是中文=\"msg\"></p>\n\n实际结果:\n<p id=\"p_01\" data=\"haha\" 还可以是中文=\"haha\"></p>\n\n```\n\n在vue所有的指令中,都是支持表达式的\n\n例如:\n\n```JavaScript\n<div class=\"name\">\n {{ a.length === 0 ? \'没有数据\' : a }}\n -{{ a.split(\'.\')[1] }}\n</div>\n```\n\n什么是表达式?\n\n```JavaScript\n// 这是语句\nvar a = 1;\n\n// 这是表达式\na.length === 0 ? \'没有数据\' : a\n\n```\n\n## 条件渲染\n\n### v-if和v-else的普通使用\n\nv-if中的布尔值为true,则渲染这个div\n\n如果if不成立,则渲染else中的代码块\n\n```HTML\n<div id=\"app\">\n <div>{{ num }}</div>\n <div id=\"if\">\n <div v-if=\"num > 0.9\">大于0.9的概率</div>\n <div v-else>v-if不满足显示我</div>\n </div>\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n new Vue({\n el: \'#app\',\n data: {\n num: Math.random(), // 一个0-1之间的随机数字\n }\n })\n</script>\n\n```\n\n### v-else-if多条件语句\n\n```HTML\n<div id=\"v-else-if\">\n <div v-if=\"num > 0.9\">大于0.9的概率</div>\n <div v-else-if=\"num > 0.6\">大于0.6的概率</div>\n <div v-else-if=\"num > 0.4\">大于0.4的概率</div>\n <div v-else-if=\"num > 0.2\">大于0.2的概率</div>\n <div v-else>所有条件都不成立</div>\n</div>\n```\n\n\n\n\n\nv-if=\"flag\",为true的时候显示\n\n为false的时候消失\n\n```JavaScript\n<div id=\"app\">\n <div class=\"name\" v-if=\"flag\">\n {{ name }}\n </div>\n <div v-else>\n if没匹配到就显示我\n </div>\n\n</div>\n<script>\n var vue = new Vue({\n el: \'#app\', // vue挂载的位置,不能是body\n data: {\n flag: false,\n name: \'枫枫\'\n }\n })\n</script>\n```\n\n## v-show与v-if的区别\n\n1. v-if如果是false,不会渲染\n2. v-show如果是false,不会显示 ` style=\"display: none;\"`\n\n体会一下v-if和v-show\n\n```HTML\n一个是看不见,但是我存在,只是我隐藏了 v-show \n一个是看不见,因为我本来就没被渲染 v-if\n```\n\n\n\n## 列表渲染\n\n主要分为遍历列表和遍历对象\n\n#### 遍历列表\n\n```JavaScript\nlis: [\n \'张三\',\n \'王伟\',\n \'张伟\',\n \'王五\',\n]\n```\n\n此时的item就是每个元素\n\n```HTML\n<ul>\n <li v-for=\"item in lis\" :key=\"item\">\n {{ item }}\n </li>\n</ul>\n```\n\nkey要唯一!!!\n\n\n\n如果需要遍历出每个元素的索引\n\n则在遍历的时候指定index\n\n```HTML\n<ul>\n <li v-for=\"(item, index) in lis\" :key=\"item\">\n {{ index }} -- {{ item }}\n </li>\n</ul>\n```\n\n#### 遍历对象\n\n```JavaScript\nobj:{\n name: \'张三\',\n age: 21,\n addr: \'北京市\',\n}\n```\n\n一个参数,就是遍历对象的值\n\n二个参数,值和键\n\n三个参数,值,键,索引\n\n```HTML\n<ul>\n <li v-for=\"item in obj\" :key=\"item\">\n 对象的值:{{ item }}\n </li>\n</ul>\n<ul>\n <li v-for=\"(item, key) in obj\" :key=\"item\">\n 对象的值:{{ item }}\n 对象的键:{{ key }}\n </li>\n</ul>\n<ul>\n <li v-for=\"(item, key, index) in obj\" :key=\"item\">\n 对象的值:{{ item }}\n 对象的键:{{ key }}\n 变量的索引:{{ index }}\n </li>\n</ul>\n```\n\n\n\n## Vue事件\n\nv-on:或者@\n\n\n```HTML\n<div id=\"app\">\n <div>\n {{ num }}\n </div>\n <div>\n <!-- 执行的方法必须在methods中-->\n <button v-on:click=\"add\">点我 +</button>\n <button @dblclick=\"num--\">点我 -1</button>\n </div>\n</div>\n\n```\n\n事件所执行的方法是要被定义在methods里面\n\n```JavaScript\nmethods: {\n add() {\n this.num ++\n }\n}\n\n```\n\n参数问题\n\n可以通过传参进行参数传递\n\n```HTML\n<button v-on:click=\"add(10)\">点我 +</button>\n\n\n...\nadd(number) {\n this.num += number\n}\n// 此时的add函数就能接收到传递进来的参数值\n```\n\n默认参数\n\n默认参数就是触发当前事件的事件对象\n\n```JavaScript\n<button id=\"add\" class=\"add_cls\" v-on:click=\"add\">点我 +</button>\n```\n\n一定是`v-on:click=\"add\"`,只写一个函数名,\n\n而不是`v-on:click=\"add()\"`,这样获取不到事件对象\n\n```JavaScript\n// 获取触发当前事件的标签\nadd(event) {\n // 触发当前事件的事件对象\n console.log(event)\n // 获取标签\n console.log(event.target)\n // 获取id,class\n console.log(event.target.id)\n console.log(event.target.className)\n}\n\n```\n\n如果有参数,想接收事件对象\n\n使用`$event`进行传递\n\n```JavaScript\n<button id=\"add\" class=\"add_cls\" v-on:click=\"add(10, $event)\">点我 +</button>\n\n...\n\nadd(number, event) {\n this.num += number\n // 触发当前事件的事件对象\n console.log(event)\n // 获取标签\n console.log(event.target)\n // 获取id,class\n console.log(event.target.id)\n console.log(event.target.className)\n}\n```\n\n\n\n### 图片轮播案例\n\n```HTML\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>图片轮播</title>\n <script src=\"../vue.js\"></script>\n</head>\n<body>\n<div id=\"app\">\n <div>\n <img :src=\"img_list[index]\" alt=\"\">\n </div>\n <div>\n <button @click=\"prevImag(index, img_list.length)\">上一张</button>\n <button @click=\"nextImag\">下一张</button>\n </div>\n</div>\n<script>\n var vue = new Vue({\n el: \'#app\', // vue挂载的位置,不能是body\n data: {\n index: 0,\n img_list: [\n \'http://h2.ioliu.cn/bing/SalzburgKrampus_ZH-CN7355658592_640x480.jpg?imageslim\',\n \'http://h2.ioliu.cn/bing/MistyTor_ZH-CN7520952555_640x480.jpg?imageslim\',\n \'http://h2.ioliu.cn/bing/Koenigsbourg_ZH-CN7675452866_640x480.jpg?imageslim\',\n \'http://h2.ioliu.cn/bing/CuvervilleIsland_ZH-CN9814166047_640x480.jpg?imageslim\',\n \'http://h2.ioliu.cn/bing/ElanValley_ZH-CN9533069637_640x480.jpg?imageslim\',\n \'http://h2.ioliu.cn/bing/WinterWaxwing_ZH-CN9435499385_640x480.jpg?imageslim\',\n ]\n },\n methods: {\n // 下一张\n nextImag() {\n // 让索引加1\n // 判断是不是最后一张,如果是就回到第一张\n if (this.index === this.img_list.length - 1) {\n this.index = 0\n return\n }\n this.index++\n },\n // 上一张\n prevImag(index, len){\n // 我希望把索引和列表长度传递进来\n if (index === 0) {\n this.index = len - 1\n return\n }\n this.index --\n }\n }\n })\n</script>\n</body>\n</html>\n```\n\n### 事件修饰符\n\n在事件处理程序中调用 `event.preventDefault()` 或 `event.stopPropagation()` 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。\n\n为了解决这个问题,Vue.js 为 `v-on` 提供了**事件修饰符**。之前提过,修饰符是由点开头的指令后缀来表示的。\n\n```HTML\n<!-- 阻止单击事件继续传播 -->\n<a v-on:click.stop=\"doThis\"></a>\n\n<!-- 提交事件不再重载页面 -->\n<form v-on:submit.prevent=\"onSubmit\"></form>\n\n<!-- 修饰符可以串联 -->\n<a v-on:click.stop.prevent=\"doThat\"></a>\n\n<!-- 只有修饰符 -->\n<form v-on:submit.prevent></form>\n\n<!-- 添加事件监听器时使用事件捕获模式 -->\n<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->\n<div v-on:click.capture=\"doThis\">...</div>\n\n<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->\n<!-- 即事件不是从内部元素触发的 -->\n<div v-on:click.self=\"doThat\">...</div>\n<!--阻止默认事件-->\n<a href=\"http://www.fengfengzhidao.com\" @click.prevent=\"my_alert\">枫枫知道</a>\n\n```\n\n\n\n#### 事件冒泡\n\n```HTML\n<div class=\"parent\" @click=\"log(\'外元素\')\">\n <div class=\"center\" @click=\"log(\'中元素\')\">\n <div class=\"child\" @click=\"log(\'里元素\')\">\n </div>\n </div>\n</div>\n```\n\n点击里元素,执行顺序\n\n![](http://python.fengfengzhidao.icu/img/20211210092420.png)\n\n点击中间的元素\n\n![](http://python.fengfengzhidao.icu/img/20211210092456.png)\n\n被父元素包裹的元素,点击事件发送后会逐级将事件向上传递\n\n```HTML\n<p>阻止事件冒泡</p>\n<div class=\"parent\" @click=\"log(\'外元素\')\">\n <div class=\"center\" @click=\"log(\'中元素\')\">\n <div class=\"child\" @click.stop=\"log(\'里元素\')\">\n </div>\n </div>\n</div>\n```\n\n添加stop事件修饰符之后,点击里元素,会阻止事件继续向上传播\n\n\n\n键盘事件\n\n```HTML\n@keydown 键盘按下\n@keyup 键盘回弹\n\n```\n\n\n\n按下回车触发\n\n支持组合键\n\n```HTML\n<input type=\"text\" v-model=\"msg\" @keyup.enter.ctrl=\"get_msg(\'上\')\">\n<input type=\"text\" v-model=\"msg\" @keyup.enter=\"get_msg(\'上\')\">\n```\n\n\n\n> 使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 `v-on:click.prevent.self` 会阻止**所有的点击**,而 `v-on:click.self.prevent` 只会阻止对元素自身的点击。\n\n#### 2.1.4新增\n\n```HTML\n<!-- 点击事件将只会触发一次 -->\n<a v-on:click.once=\"doThis\"></a>\n```\n\n\n\n### 按键修饰符\n\n最常见的可能就是在一个输入框中,判断用户是否按下了回车键\n\n```HTML\n<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->\n<input v-on:keyup.enter=\"submit\">\n```\n\n一些必要的按键名称\n\n```HTML\n.enter\n.tab\n.delete (捕获“删除”和“退格”键)\n.esc\n.space\n.up\n.down\n.left\n.right\n```\n\n组合按键\n\n```HTML\n<!-- Alt + C -->\n<input v-on:keyup.alt.67=\"clear\">\n\n<!-- Ctrl + Click -->\n<div v-on:click.ctrl=\"doSomething\">Do something</div>\n```\n\n\n\n\n\n\n\n## 计算属性\n\n- 调用的时候不用加括号(只是一个属性)\n- 可以监听属性变化,属性变化,计算属性重新执行\n- 并且有缓存(多个计算属性,只执行一次)\n\n和methods的区别\n\n属性变化,methods方法全部重新获取\n\n```HTML\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>计算属性</title>\n <script src=\"../vue.js\"></script>\n</head>\n<body>\n<div id=\"app\">\n <div>{{ name }}</div>\n <div>{{ name.split(\'\').reverse().join(\'\') }}</div>\n <div>{{ name.length === 5 ? \'五言绝句\' : \'七言绝句\' }}</div>\n <div v-if=\"name.length === 5\">五言绝句</div>\n <div v-else-if=\"name.length === 7\">七言绝句</div>\n <div v-else>错了</div>\n\n <!-- 计算属性 -->\n <div>{{ getName }}</div>\n <div>{{ getName }}</div>\n <div>{{ getName }}</div>\n <div>{{ getName }}</div>\n <div>{{ getName }}</div>\n <div>{{ getName }}</div>\n <div>{{ getName }}</div>\n <div>{{ get_data_name() }}</div>\n <div>{{ get_data_name() }}</div>\n <div>{{ get_data_name() }}</div>\n <div>{{ get_data_name() }}</div>\n <div>{{ get_data_name() }}</div>\n\n <button @click=\"getsub\">\n 点我\n </button>\n <span>{{ num }}</span>\n <button @click=\"set_name\">计算属性</button>\n</div>\n<script>\n var vue = new Vue({\n el: \'#app\', // vue挂载的位置,不能是body\n data: {\n name: \'床前明月光\',\n num: 0\n },\n methods: {\n get_data_name() {\n console.log(\'属性方法\')\n return this.name.split(\'\').reverse().join(\'\')\n },\n getsub(e) {\n this.num ++\n },\n set_name(){\n this.name += \'a\'\n }\n },\n\n computed: {\n getName() {\n console.log(\'计算属性\')\n return this.name.split(\'\').reverse().join(\'\')\n }\n }\n })\n</script>\n</body>\n</html>\n```\n\n### computed与watch,methods的区别\n\nmethods:可以放入函数,并且没有缓存\n\nwatch:\n\n监听,当数据发送变化时,才会触发\n\n可以得到现在的值和过去的值\n\n还可以监听路由变化\n\n和属性同名\n\n## 自定义过滤器\n\n创建一个过滤器\n\n```JavaScript\n// 自定义过滤器\nfilters:{\n // 截取最后一个字符\n getLastChar(item){\n return item.substr(item.length-1,1)\n }\n}\n```\n\n使用过滤器\n\n```HTML\n<li v-for=\"item in student_list\" :key=\"item.id\">\n {{item.name|getLastChar }} -- {{ item.addr }}\n</li>\n```\n\n### 时间过滤器\n\n![](http://python.fengfengzhidao.com/1031/20211208215339.png)\n\n```HTML\n<div id=\"app\">\n <div>\n 当前时间:{{ now|get_date }}\n </div>\n <ul>\n <li v-for=\"item in date_list\" :key=\"item.id\">\n id:{{ item.id }} 时间:{{ item.date|get_date }}\n </li>\n </ul>\n <div>\n 时间过滤\n </div>\n <ul>\n <li v-for=\"item in date_list\" :key=\"item.id\">\n id:{{ item.id }} 时间:{{ item.date|time_to_filter }}\n </li>\n </ul>\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n function getDateDiff(datestamp) {\n var publishTime = datestamp / 1000,\n d_seconds,\n d_minutes,\n d_hours,\n d_days,\n timeNow = parseInt(new Date().getTime() / 1000),\n d,\n date = new Date(publishTime * 1000),\n Y = date.getFullYear(),\n M = date.getMonth() + 1,\n D = date.getDate(),\n H = date.getHours(),\n m = date.getMinutes(),\n s = date.getSeconds();\n //小于10的在前面补0\n if (M < 10) {\n M = \'0\' + M;\n }\n if (D < 10) {\n D = \'0\' + D;\n }\n if (H < 10) {\n H = \'0\' + H;\n }\n if (m < 10) {\n m = \'0\' + m;\n }\n if (s < 10) {\n s = \'0\' + s;\n }\n d = timeNow - publishTime;\n d_days = parseInt(d / 86400);\n d_hours = parseInt(d / 3600);\n d_minutes = parseInt(d / 60);\n d_seconds = parseInt(d);\n if (d_days > 0 && d_days < 30) {\n return d_days + \'天前\';\n } else if (d_days <= 0 && d_hours > 0) {\n return d_hours + \'小时前\';\n } else if (d_hours <= 0 && d_minutes > 0) {\n return d_minutes + \'分钟前\';\n } else if (d_seconds < 60) {\n if (d_seconds <= 0) {\n return \'刚刚发表\';\n } else {\n return d_seconds + \'秒前\';\n }\n } else if (d_days >= 30) {\n return Y + \'-\' + M + \'-\' + D + \' \' + H + \':\' + m;\n }\n }\n\n var vue = new Vue({\n el: \'#app\',\n data: {\n now: \'2021-12-8 22:01:11\',\n date_list: [\n {id: 1, date: \'2021-12-8 22:02:11\'},\n {id: 2, date: \'2021-12-6 22:02:21\'},\n {id: 3, date: \'2021-12-8 21:01:14\'},\n {id: 4, date: \'2021-12-5 20:12:11\'},\n ]\n },\n filters: {\n // 年-月-日\n get_date(date_str) {\n // date,传递的参数\n\n // 字符串转时间对象\n let date = new Date(date_str)\n return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`\n },\n time_to_filter(date_str) {\n // 字符串->对象->时间戳\n // 和当前时间做差,算出相差的时间(多少秒,多少分)\n // 字符串转时间对象->时间戳\n let datestamp = new Date(date_str).getTime()\n return getDateDiff(datestamp)\n }\n }\n })\n</script>\n```\n\n### 参数问题\n\n自定义过滤器也是可以接受参数,它的书写语法是\n\n```JavaScript\n<li v-for=\"item in date_list\" :key=\"item.id\">\n id:{{ item.id }} 时间:{{ item.date|time_to_filter(\'a\', \'b\') }}\n</li>\n\n\n...\n\nfilters: {\n ...\n time_to_filter(date_str, a, b) {\n // date_str -> \'自身的值\'\n // a -> \'a\'\n // b -> \'b\'\n \n return date_str\n }\n}\n\n```\n\n过滤器方法的第一个参数就是调用者本身的值,第二个参数之后就是调用的实参\n\n并且支持链式过滤器\n\n```HTML\n<div>{{now|get_now|get_now1}}</div>\n```\n\n\n\n\n\n## 全局方法\n\n需要将属性和方法挂载到`Vue.prototype`上\n\n```JavaScript\nVue.prototype.$com = \"全局变量\"\n\nlet global_method = ()=>{\n return \"全局方法\"\n}\nfunction add(){\n return \"全局 add 方法\"\n}\nVue.prototype.$global_method = global_method\nVue.prototype.$add = add\n```\n\n使用\n\n```HTML\n<div>\n {{ $global_method() }}\n</div>\n<div>\n {{ $add() }}\n</div>\n```\n\n### 全局过滤器\n\n```JavaScript\n// 全局过滤器\nlet global_filter = (item) => {\n return item + \'--global\'\n}\n// 注册全局过滤器 (过滤器名称,方法)\nVue.filter(\'global_filter\', global_filter)\n```\n\n使用全局过滤器\n\n```HTML\n<div>\n {{ $com|global_filter }}\n</div>\n```\n\n\n\n## 局部组件\n\n```HTML\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>局部组件</title>\n</head>\n<body>\n<div id=\"app\">\n <App></App> <!--使用子组件-->\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n // app 组件 html css js\n const App = {\n data() {\n // 在组件中使用数据,需要 使用函数,返回值返回对象 data(){ return {} }\n return {msg: \'hello\'}\n },\n template: `\n <div>\n <h3>我是app组件</h3>\n <p>{{ msg }}</p>\n <button @click=\"handleClick\">按钮</button>\n </div>\n\n `,\n methods: {\n handleClick() {\n this.msg = \'world\'\n }\n }\n }\n new Vue({\n el: \'#app\',\n data: {},\n components: {\n App // 挂载子组件\n }\n })\n</script>\n</body>\n</html>\n```\n\n## 全局组件\n\n```HTML\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>局部组件</title>\n</head>\n<body>\n<div id=\"app\">\n <App></App> <!--使用子组件-->\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n // app 组件 html css js\n // 只要创建组件,就可以在template中使用\n Vue.component(\'Vheader\', {\n template: `\n <div>\n <span>我是导航组件</span>\n </div>\n `\n })\n Vue.component(\'Vfooter\', {\n template: `\n <div>\n <span>我是底部组件</span>\n </div>\n `\n })\n Vue.component(\'Vsider\', {\n data() {\n return {msg: \'侧边栏\'};\n },\n template: `\n <div>\n <span class=\"sider_title\">我是侧边栏组件</span>\n <span>{{ msg }}</span>\n </div>\n `,\n })\n const Vbtn = {\n template: `\n <button>按钮</button>\n `\n }\n\n const App = {\n data() {\n // 在组件中使用数据,需要 使用函数,返回值返回对象 data(){ return {} }\n return {msg: \'hello\'}\n },\n template: `\n <div>\n <Vheader></Vheader>\n <Vbtn></Vbtn>\n <Vbtn></Vbtn>\n <Vbtn></Vbtn>\n <Vsider></Vsider>\n <Vfooter></Vfooter>\n <h3>我是app组件</h3>\n <p>{{ msg }}</p>\n <button @click=\"handleClick\">按钮</button>\n </div>\n\n `,\n components: {\n Vbtn \n },\n methods: {\n handleClick() {\n this.msg = \'world\'\n }\n }\n }\n new Vue({\n el: \'#app\',\n data: {},\n components: {\n App // 挂载子组件\n }\n })\n</script>\n</body>\n</html>\n```\n\n## 组件通信\n\n### 父传子\n\n父传子:通过`props`来进行通信\n\n```HTML\n1. 在自组件中声明props接收在父组件挂载的属性\n2. 可以在自组件的template在任意使用\n3, 在父组件绑定自定义的属性\n```\n\n\n\n### props传入一个对象\n\n```JavaScript\nprops: [\'title\', \'likes\', \'isPublished\', \'commentIds\', \'author\']\n\n\nprops: {\n title: String,\n likes: Number,\n isPublished: Boolean,\n commentIds: Array,\n author: Object,\n callback: Function,\n contactsPromise: Promise // or any other constructor\n}\n\n\nprops: {\n data: {\n type: String, // 类型\n required: true, // 必填项\n default: \'张三\' // 如果没传值,那么这个默认值就是它\n }\n}\n\n```\n\n\n\n```HTML\n<div id=\"app\">\n <App></App> <!--使用子组件-->\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n Vue.component(\'Child\', {\n template: `\n <div>\n <h3>我是子组件</h3>\n <h4>{{ childData }}</h4>\n </div>\n `,\n props: [\'childData\']\n })\n const App = {\n data() {\n // 在组件中使用数据,需要 使用函数,返回值返回对象 data(){ return {} }\n return {msg: \'我是父组件传递的值\'}\n },\n template: `\n <div>\n <Child :childData=\"msg\"></Child>\n <p>{{ msg }}</p>\n </div>\n\n `,\n }\n new Vue({\n el: \'#app\',\n data: {},\n components: {\n App // 挂载子组件\n }\n })\n</script>\n```\n\n\n\n### created与mounted\n\n```JavaScript\ncreated(){\n console.log(this.data, 1)\n},\nmounted(){\n console.log(this.data, 2)\n}\n```\n\n\n\n### 子传父\n\n```HTML\n1. 在父组件中,自组件上绑定自定义事件\n2. 在自组件中,触发原生的事件,在事件函数通过this.$emit触发自定义的事件\n```\n\n父组件\n\n```JavaScript\n<comment1 v-on:eff=\"eff\"></comment1>\n\ncomponents: {\n comment1\n},\nmethods: {\n eff(data) {\n // data 是子组件传递的数据\n console.log(\'父组件被调用了\', data)\n }\n}\n\n```\n\n子组件\n\n```JavaScript\nlet comment1 = {\n template: `\n <div>\n <ul>\n <li>兰州拉面</li>\n <li>哈尔滨啤酒</li>\n <li>四川担担面</li>\n <button @click=\"add\">点我触发父组件方法</button>\n </ul>\n </div>`,\n methods: {\n add() {\n this.$emit(\'eff\', {name: \'子组件传来的数据\'})\n }\n }\n\n}\n```\n\n## 平行组件\n\n```HTML\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>平行组件</title>\n <style>\n body {\n margin: 0;\n }\n\n #app {\n display: flex;\n }\n\n #app > div {\n width: 50%;\n height: 200px;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n #gouwuc {\n background-color: #3a8ee6;\n }\n\n #get {\n background-color: #b3d9d9;\n }\n </style>\n</head>\n<body>\n<div id=\"app\">\n <App1 id=\"gouwuc\"></App1> <!--使用子组件-->\n <App2 id=\"get\"></App2> <!--使用子组件-->\n</div>\n<script src=\"../vue.js\"></script>\n<script>\n let Bus = new Vue()\n let App1 = {\n data() {\n return {\n num: 100\n }\n },\n template: `\n <div>\n 购物车 商品总数{{ num }}\n </div>`,\n mounted(){\n Bus.$on(\'add\', (data)=>{\n this.num ++\n })\n }\n }\n let App2 = {\n data() {\n return {\n num: 100\n }\n },\n methods: {\n add() {\n Bus.$emit(\'add\', {msg: \'你的好兄弟又下单啦\'})\n }\n },\n template: `\n <div>\n <button @click=\"add\">加入购物车</button>\n </div>`\n }\n new Vue({\n el: \'#app\',\n data: {},\n components: {\n App1,\n App2,\n }\n })\n</script>\n</body>\n</html>\n```\n\n多次嵌套取值\n\n```HTML\n1. provide 提供变量 函数(){return {} },\n2. inject 接收变量 inject: [],\n```\n\n\n\n## 匿名插槽\n\n```JavaScript\nlet base_layout = {\n data() {\n return {}\n },\n template: `\n <div>\n <header>\n <slot>我是页头</slot>\n </header>\n </div>`\n}\nnew Vue({\n el: \'#app\',\n components: {\n base_layout\n }\n})\n```\n\n在模板中把想要替换的东西放在`<slot>`标签中,这就是一个占位符\n\n```HTML\n<base_layout>实际的内容</base_layout>\n```\n\n这样就会将标签中的内容去代替slot中的内容\n\n如果slot都没有名字,那么如果有多个slot,就会全部进行替换\n\n## 具名插槽\n\n如果你的模板中需要有多个地方被替换\n\n那么匿名插槽就不太合适了,我们给每个插槽都起一个别名\n\n```JavaScript\nlet base_layout = {\n data() {\n return {}\n },\n template: `\n <div>\n <header>\n <slot name=\"header\">我是页头</slot>\n </header>\n <main>\n <slot name=\"main\">我是内容</slot>\n </main>\n <footer>\n <slot name=\"footer\">我是页脚</slot>\n </footer>\n </div>`\n}\n```\n\n这样我们在进行替换的时候,指明要替换哪个slot就OK了\n\n```HTML\n<base_layout>\n <template v-slot:header>\n 头部\n </template>\n <template v-slot:main>\n 身体\n </template>\n <template v-slot:footer>\n 尾部\n </template>\n</base_layout>\n```\n\n注意v-slot的写法\n\n```HTML\nv-slot:header\n```\n\n`v-slot:` 可以简写为 #\n\n```HTML\n <base_layout>\n <template v-slot:header>\n <child></child>\n <div>\n 哈哈哈哈\n </div>\n </template>\n <template #main>\n 身体\n </template>\n <template v-slot:footer>\n 尾部\n </template>\n</base_layout>\n```\n\n> 我们在替换的时候,是可以写任意标签的,也就是说,在替换的时候,你也可以将组件写入插槽中\n\n```HTML\n<base_layout>\n <template v-slot:header>\n <child></child>\n <div>\n 哈哈哈哈\n </div>\n </template>\n <template v-slot:main>\n 身体\n </template>\n <template v-slot:footer>\n 尾部\n </template>\n</base_layout>\n```\n\n\n\n## 作用域插槽\n\n```JavaScript\nlet base_layout = {\n data() {\n return {\n user: {\n name: \'枫枫\',\n xin: \'知道\'\n }\n }\n },\n template: `\n <div>\n <main>\n <slot :user=\"user\">{{ user.xin }}</slot>\n </main>\n </div>`\n}\n```\n\n在子组件中,我在插槽里面显示的是user的xin,如果我想让它显示user的name应该怎么做呢\n\n如果我们直接在父组件调用的时候这样写\n\n```HTML\n<base_layout>\n {{ user.name }}\n</base_layout>\n```\n\n这是错误的写法,因为我们的user是被定义再自组件中的,在父组件中就无法使用这个user,所以就会报错啦\n\n那么我们就应该将这个user对象传递给父组件\n\n在子组件中\n\n```HTML\n<slot :user=\"user\">{{ user.xin }}</slot>\n```\n\n通过动态属性的方式将user传递给父组件\n\n在父组件中\n\n```HTML\n<base_layout>\n <template v-slot:default=\"slotProps\">\n {{ slotProps.user.name }}\n </template>\n</base_layout>\n```\n\n接收传递来的user即可\n\nslotProps可以是你自己定义的名字,它里面存储的是这样的\n\n```HTML\n{ \"user\": { \"name\": \"枫枫\", \"xin\": \"知道\" } }\n```\n\n所以我们将slotProps中的user中的name传递给子组件,就可以做到数据动态替换\n\n\n\n如果你的组件中,有且只有一个默认插槽,那么在替换的时候,是可以这么做的\n\n```HTML\n<base_layout v-slot:default=\"slotProps\">\n {{ slotProps }}\n</base_layout>\n```\n\n但是,如果出现了具名插槽,这样会导致作用域混乱\n\n我们应该这样使用\n\n```JavaScript\nlet base_1 = {\n data(){\n return {\n user: {\n name: \'枫枫知道\',\n age: 21\n }\n }\n },\n template: `\n <div>\n <header>\n 我的名字是 <slot :user=\"user\" name=\"name\">{{ user.name }}</slot>,年龄是<slot :user=\"user\" name=\"age\">{{ user.age }}</slot>\n </header>\n </div>`\n}\n```\n\n\n\n```HTML\n<base_1>\n <template v-slot:name>张子枫</template>\n <template v-slot:age=\"slotBase\">{{ slotBase }}</template>\n</base_1>\n```\n\n\n\n## 动态组件\n\n> `<component>`元素是vue 里面的一个内置组件。\n在<component>里面使用 v-bind: is,可以实现动态组件的效果。\n\n\n\n\n\n\n\n\n\n\n\n## 自定义指令\n\n前面使用的v-if, v-show,以及v-for这些都是Vue为我们提供的内置指令\n\n当然,我们也可以自己自定义一个指令\n\n### 局部自定义指令\n\n```JavaScript\ndirectives: {\n focus: {\n // 指令的定义\n // 使用这个指令就会聚焦在输入框中\n inserted: function (el) {\n el.focus()\n }\n }\n}\n```\n\n使用\n\n```HTML\n<input type=\"text\" v-focus>\n```\n\n在focus中有几个钩子函数,需要了解\n\n- `bind`:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。\n- `inserted`:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。\n- `update`:所在组件的 VNode 更新时调用,**但是可能发生在其子 VNode 更新之前**。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。','2022-02-10 10:20:46.600379','2022-03-10 22:50:05.179944',1,1,79,0,2,0,1,'枫枫','枫枫知道个人博客',21,NULL,NULL,25679),(33,'枫枫知道--React全系列课程','安装react包Python npm i react react-dom使用react```HTMLreact基本使用// 2.创建react元素 // 参数一:元素名称','## 安装react包\r\n\r\n```Python\r\nnpm i react react-dom\r\n```\r\n\r\n使用react\r\n\r\n```HTML\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <title>react基本使用</title>\r\n\r\n</head>\r\n<body>\r\n<div id=\"root\"></div>\r\n<!--1. 引入react和react-dom两个js文件,注意顺序-->\r\n<!--注意与node_modules的层级关系-->\r\n<script src=\"../node_modules/react/umd/react.development.js\"></script>\r\n<script src=\"../node_modules/react-dom/umd/react-dom.development.js\"></script>\r\n<script>\r\n // 2.创建react元素\r\n // 参数一:元素名称\r\n // 参数二:元素属性\r\n // 参数三:元素的节点\r\n const title = React.createElement(\"h1\", null, \"hello react\")\r\n // 3.渲染react元素\r\n // 参数一:要渲染的react元素\r\n // 参数二:元素要渲染的位置,挂载点\r\n ReactDOM.render(title, document.getElementById(\'root\'))\r\n</script>\r\n</body>\r\n</html>\r\n```\r\n\r\n常用方法\r\n\r\n1. `react-createElement`方法\r\n\r\n```JavaScript\r\n/* \r\n参数一:元素名称\r\n参数二:元素属性,对象\r\n参数三:第三个及其之后的参数都是元素的子节点\r\n* */\r\nconst title = React.createElement(\r\n \'p\',\r\n {title: \'我是标题\', alt: \'我是xxx\'},\r\n React.createElement(\'span\', null, \'枫枫知道\')\r\n)\r\n```\r\n1. `react-render`方法\r\n\r\n```JavaScript\r\n// 参数一:要渲染的react元素\r\n// 参数二:元素要渲染的位置,挂载点\r\nReactDOM.render(title, document.getElementById(\'root\'))\r\n```\r\n\r\n## react脚手架的使用\r\n\r\n```JavaScript\r\n// 脚手架安装\r\nnpx create-react-app my_app\r\n// 启动项目,进入创建的app\r\nnpm start\r\n```\r\n\r\n![](http://python.fengfengzhidao.icu/img/20211206092109.png)\r\n\r\n看到这个界面就说明成功启动了,恭喜你,离升职加薪又近了一步\r\n\r\n### npx命令介绍\r\n\r\n1. npm v5.2.0 引入的一条命令\r\n2. 目的:提升包内提供的命令行工具的使用体验\r\n3. 原来:先安装脚手架包,再使用这个包中提供的命令\r\n4. 现在:无需安装脚手架包,就可以直接使用这个包提供的命令\r\n\r\n初始化项目:\r\n\r\n```JavaScript\r\nnpx create-react-app my_app // 推荐\r\nnpm init react-app my_app\r\nyarn create react-app my_app\r\n```\r\n\r\n### 脚手架中使用react\r\n\r\n```JavaScript\r\n// 1. 导入文件\r\nimport React from \'react\';\r\nimport ReactDOM from \'react-dom\';\r\n\r\n// 2.创建react元素\r\nconst title = React.createElement(\'h1\', null, \'hello react!!!\')\r\n\r\n// 3. 渲染元素\r\nReactDOM.render(title, document.getElementById(\'root\'))\r\n```\r\n\r\n# JSX的学习\r\n\r\n什么是jsx\r\n\r\ncreateElement的问题,写的太麻烦了,所以诞生了jsx\r\n\r\njsx是JavaScript XML的简写,表示在JavaScript中书写的xml格式的代码\r\n\r\n优势:声明式语法更加直观,与HTML结构相同\r\n\r\n使用jsx\r\n\r\n```JavaScript\r\n// 使用jsx\r\nconst title = <h1 id=\"枫枫\">\r\n hello world\r\n <span>这是一个span</span>\r\n </h1>\r\n```\r\n\r\n### 为什么可以在脚手架中使用jsx语法???\r\n\r\n1. jsx不是标准的ECMAScript语法,他是ECMAScript的语法扩展\r\n2. 需要使用babel编译处理,才能在浏览器环境中使用\r\n3. create-react-app脚手架中已经默认有该配置,无需手动配置\r\n4. 编译jsx语法的包为:@babel/preset-react\r\n\r\n### jsx的注意点\r\n\r\n1. jsx的属性名为小驼峰\r\n2. 特殊属性\r\n\r\n```JavaScript\r\nclass -> className\r\nfor -> htmlFor\r\ntabindex -> tabIndex\r\n```\r\n\r\n 例如\r\n\r\n```JavaScript\r\nconst title = <h1 className=\"title\">我是枫枫</h1>\r\n```\r\n1. 如果一个元素没有子节点,直接使用单标签即可\r\n\r\n 例如\r\n\r\n```JavaScript\r\nconst title = <h1 className=\"title\">我是枫枫 <span/></h1>\r\n```\r\n1. 推荐使用小括号包裹jsx语法\r\n\r\n 例如\r\n\r\n```JavaScript\r\nconst title = (\r\n <h1 className=\"title\">我是枫枫\r\n <h2>哈哈哈</h2>\r\n <span/></h1>\r\n)\r\n```\r\n1. jsx最外层只能有一个闭合标签\r\n\r\n\r\n\r\n## 在jsx中使用js表达式\r\n\r\n注意点:\r\n\r\n1. 语法:`{ js表达式 }`\r\n2. 使用单大括号,而不是双大括号\r\n\r\n```JavaScript\r\nlet name = \'枫枫知道\'\r\nconst title = (\r\n <h1 className=\"title\">我是{name}</h1>\r\n)\r\n```\r\n\r\n### 条件渲染\r\n\r\n```JavaScript\r\n// 条件语句\r\nlet isloading = false\r\nconst loadData = () => {\r\n return isloading ? (<div>loading...</div>) : (<div>数据加载完成</div>)\r\n}\r\n\r\nconst title = (\r\n <h1>条件渲染\r\n {loadData()}</h1>\r\n)\r\n```\r\n\r\n### 列表渲染\r\n\r\n使用数组的map方法,将数组的每个元素映射为一个li元素\r\n\r\n渲染列表的时候也要添加key属性,key属性的值要保证唯一\r\n\r\n原则:map()遍历谁,就给谁添加key属性\r\n\r\n尽量避免使用索引号作为key\r\n\r\n```JavaScript\r\n// 列表渲染\r\nconst sons = [\r\n {id: 1, name: \'像我这样的人\'},\r\n {id: 2, name: \'痴心妄想\'},\r\n {id: 3, name: \'南山南\'},\r\n {id: 4, name: \'我的未来不是梦\'},\r\n]\r\nconst list = (\r\n <ul>\r\n {sons.map(item => <li key={item.id} id={item.id}>{item.name}</li>)}\r\n </ul>\r\n)\r\n```\r\n\r\n### 样式处理\r\n\r\n行内样式(不推荐)\r\n\r\n```JavaScript\r\nconst list = (\r\n <ul>\r\n {sons.map(item => <li style={{color: \'red\', backgroundColor: \'#333\'}} key={item.id} id={item.id}>{item.name}</li>)}\r\n </ul>\r\n)\r\n```\r\n\r\n类名—className(推荐)\r\n\r\n```JavaScript\r\n// 引入样式\r\nimport \'./css/index.css\';\r\n// 样式使用\r\nconst title = (\r\n <h2 className=\"title\">\r\n 枫枫知道\r\n </h2>\r\n)\r\n```\r\n\r\n\r\n\r\n## React组件\r\n\r\nReact组件的两种创建方式\r\n\r\n### 使用函数创建组件\r\n\r\n- 约定1:函数名必须是大写字母开头\r\n- 约定2:函数组件必须要有返回值,表示该组件的结构\r\n- 如果返回值为null,表示不渲染任何内容\r\n\r\n```JavaScript\r\n// 函数组件\r\n\r\nfunction Hello(){\r\n return (\r\n <h2>这是我的第一个函数组件</h2>\r\n )\r\n}\r\n\r\nconst title = (\r\n <Hello/>\r\n)\r\n```\r\n\r\n函数组件的使用\r\n\r\n- 用函数名作为标签名\r\n- 组件标签可以是单标签也可以是双标签\r\n\r\n也可以使用箭头函数\r\n\r\n```JavaScript\r\nconst Hello = () => <h2>这是我的第一个函数组件</h2>\r\n\r\nconst title = (\r\n <Hello/>\r\n)\r\n```\r\n\r\n### 使用类创建组件\r\n\r\n- 类组件:使用ES6的class创建的组件\r\n- 约定1:类名必须大写\r\n- 约定2:类组件应该继承React.Component父类,从而可以使用父类中提供的方法和属性\r\n- 约定3:类组件必须提供render() 方法\r\n- 约定4:render()方法必须要有返回值,表示该组件的结构\r\n\r\n```JavaScript\r\n// 类组件\r\nclass Hello extends React.Component {\r\n render() {\r\n return <div>这是一个类组件</div>\r\n }\r\n}\r\n\r\nconst title = (\r\n <Hello/>\r\n)\r\n```\r\n\r\n### 抽离为单独的js文件\r\n\r\n组件多了之后,就应该把组件单独放在一个js文件中\r\n\r\n1. 创建一个Hello.js文件\r\n\r\n```JavaScript\r\nimport React from \"react\";\r\n\r\nclass Hello extends React.Component {\r\n render() {\r\n return <div>这是一个类组件</div>\r\n }\r\n}\r\n\r\n// 导出类组件\r\nexport default Hello\r\n```\r\n1. 在index.js中引入该组件\r\n\r\n```JavaScript\r\nimport Hello from \"./Hello\";\r\n\r\nconst title = (\r\n <Hello/>\r\n)\r\n\r\n```\r\n\r\n## 事件处理\r\n\r\nreact事件绑定语法与DOM事件语法相似\r\n\r\n语法:on+事件名称={ 事件 处理程序},比如:onClick={() => {} }\r\n\r\n注意:react中的时间也才用小驼峰命名法\r\n\r\n基于类组件\r\n\r\n- 使用this.函数名触发\r\n\r\n```JavaScript\r\nclass Hello extends React.Component {\r\n handleClick() {\r\n console.log(\'单击事件触发了!\')\r\n }\r\n\r\n render() {\r\n return <div onClick={this.handleClick}>这是一个类组件</div>\r\n }\r\n}\r\n```\r\n\r\n基于函数组件\r\n\r\n- 函数写在函数里面\r\n- 使用函数名触发\r\n\r\n```JavaScript\r\n// 函数组件\r\nfunction App() {\r\n function handleClick() {\r\n console.log(\'单击事件触发了\')\r\n }\r\n\r\n return (\r\n <div onClick={handleClick}>我是一个app函数组件</div>\r\n )\r\n}\r\n```\r\n\r\n## 事件对象\r\n\r\n- 可以通过事件处理程序的参数获取到事件对象\r\n- React中的事件对象叫做:合成事件(对象)\r\n- 合成事件:兼容所有浏览器,无需担心跨浏览器兼容问题\r\n\r\n```JavaScript\r\nfunction App() {\r\n function handleClick(e) {\r\n // 阻止浏览器默认行为\r\n e.preventDefault()\r\n // 获取当前的这个标签 e.target\r\n console.log(\'事件对象\', e.target)\r\n }\r\n\r\n return (\r\n <a onClick={handleClick} href=\"http://www.baidu.com\">放行,我不会跳转</a>\r\n )\r\n}\r\n```\r\n\r\n## 有状态组件,无状态组件\r\n\r\n- 函数组件—无状态组件\r\n- 类组件—有状态组件\r\n\r\n函数组件只负责数据的展示(静)\r\n\r\n类组件有自己的状态,负责更新UI,让页面“动”起来\r\n\r\n### state的基本使用\r\n\r\n- 状态(state)即数据,是组件内部的私有数据,只能在组件内部使用\r\n- state的值是对象,表示一个组件内有多个数据\r\n\r\n```JavaScript\r\nclass Count extends React.Component {\r\n // constructor() {\r\n // super();\r\n // // 初始化state\r\n // this.state = {\r\n // count: 0\r\n // }\r\n // }\r\n // 简化语法初始化\r\n state = {\r\n count: 0,\r\n }\r\n render() {\r\n return (\r\n <div>\r\n <span>计数器:</span>\r\n </div>\r\n )\r\n }\r\n}\r\n```\r\n\r\n读取状态\r\n\r\n```JavaScript\r\n<span>计数器:{this.state.count}</span>\r\n```\r\n\r\n### setState修改状态\r\n\r\n- 状态是可变的\r\n- 语法:this.setState({要修改的数据})\r\n- 注意:不要直接修改state中的值,这是错误的!!!\r\n\r\n```JavaScript\r\nclass Count extends React.Component {\r\n state = {\r\n count: 0,\r\n }\r\n render() {\r\n return (\r\n <div>\r\n <p>计数器:{this.state.count}</p>\r\n <button onClick={() => {\r\n this.setState({\r\n count: this.state.count + 1\r\n })\r\n }}> +1\r\n </button>\r\n </div>\r\n )\r\n }\r\n}\r\n\r\n```\r\n\r\n思想:数据驱动视图\r\n\r\n### 从jsx中抽离事件处理程序\r\n\r\n如果是抽离出单独的方法,在调用方法的时候,在函数体中this就不再是原来那个this,而是undefined\r\n\r\n```JavaScript\r\n<button onClick={this.onIncrement}> +1</button>\r\n// 这样会报错\r\n```\r\n\r\n正确的写法是使用箭头函数去调用要执行的方法\r\n\r\n```JavaScript\r\n<button onClick={() => this.onIncrement()}> +1</button>\r\n```\r\n\r\n```JavaScript\r\n\r\nclass Count extends React.Component {\r\n state = {\r\n count: 0,\r\n }\r\n\r\n onIncrement() {\r\n this.setState({\r\n count: this.state.count + 1\r\n })\r\n }\r\n\r\n render() {\r\n return (\r\n <div>\r\n <p>计数器:{this.state.count}</p>\r\n <button onClick={() => this.onIncrement()}> +1\r\n </button>\r\n </div>\r\n )\r\n }\r\n}\r\n```\r\n\r\n### 事件绑定this指向\r\n\r\n```JavaScript\r\nrender() {\r\n return (\r\n <div>\r\n <p>计数器:{this.state.count}</p>\r\n <button onClick={() => this.onIncrement()}> +1\r\n </button>\r\n </div>\r\n )\r\n}\r\n```\r\n\r\n在button中的this是指向的是render这个实例\r\n\r\n```JavaScript\r\nonIncrement() {\r\n this.setState({\r\n count: this.state.count + 1\r\n })\r\n}\r\n```\r\n\r\n在`onIncrement`方法中的this就是button中的this,也就是render\r\n\r\n#### 箭头函数\r\n\r\n- 利用箭头函数自身不绑定this的特点\r\n- render()方法中的this为组件实例,可以获取到setState()\r\n\r\n\r\n\r\n#### 使用bind绑定this\r\n\r\n- 利用ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起\r\n\r\n```JavaScript\r\nclass Count extends React.Component {\r\n state = {\r\n count: 0,\r\n }\r\n\r\n constructor() {\r\n super();\r\n this.onIncrement = this.onIncrement.bind(this)\r\n }\r\n\r\n onIncrement() {\r\n this.setState({\r\n count: this.state.count + 1\r\n })\r\n }\r\n\r\n render() {\r\n return (\r\n <div>\r\n <p>计数器:{this.state.count}</p>\r\n <button onClick={this.onIncrement}> +1</button>\r\n {/*<button onClick={() => this.onIncrement()}> +1</button>*/}\r\n </div>\r\n )\r\n }\r\n}\r\n```\r\n\r\n#### class的实例方法(推荐)\r\n\r\n```JavaScript\r\nonIncrement = () => {\r\n this.setState({\r\n count: this.state.count + 1\r\n })\r\n}\r\n```\r\n\r\n总结:\r\n\r\n1. class的实例方法(推荐)\r\n2. 箭头函数\r\n3. bind\r\n\r\n## 表单处理\r\n\r\n受控组件与非受控组件\r\n\r\n### 受控组件\r\n\r\n- HTML中的表单元素是可输入的,也就是有自己的可变状态\r\n- 而react的可变状态通常是保存在state中,并且只能通过setState()方法来修改\r\n- react将表单元素值value绑定到一起,由state的值来控制表单元素的值\r\n- 受控组件,其值受到react控制的表单元素\r\n\r\n示例:\r\n\r\n1. 文本框,富文本框,下拉框\r\n2. 复选框\r\n\r\n```JavaScript\r\nclass Txt extends React.Component {\r\n state = {\r\n txt: \'\',\r\n content: \'\',\r\n city: \'bj\',\r\n isChecked: false,\r\n }\r\n // 处理文本框值变化\r\n handleChange = (e) => {\r\n this.setState({\r\n txt: e.target.value\r\n })\r\n }\r\n // 处理富文本框的值变化\r\n handleContent = (e) => {\r\n this.setState({\r\n content: e.target.value\r\n })\r\n }\r\n // 处理下拉框值变化\r\n handleCity = (e) => {\r\n this.setState({\r\n city: e.target.value\r\n })\r\n }\r\n // 复选框发送变化\r\n handleCheck = (e) => {\r\n this.setState({\r\n isChecked: e.target.checked\r\n })\r\n }\r\n\r\n render() {\r\n return (\r\n <div>\r\n {/*文本框*/}\r\n <div>\r\n <input type=\"text\" value={this.state.txt} onChange={this.handleChange}/>\r\n </div>\r\n {/*富文本框*/}\r\n <div>\r\n <textarea value={this.state.content} onChange={this.handleContent}></textarea>\r\n </div>\r\n {/*下拉框*/}\r\n <div>\r\n <select value={this.state.city} onChange={this.handleCity}>\r\n <option value=\"sh\">上海</option>\r\n <option value=\"bj\">北京</option>\r\n <option value=\"cd\">成都</option>\r\n <option value=\"cs\">长沙</option>\r\n </select>\r\n </div>\r\n {/*复选框*/}\r\n <div>\r\n <input type=\"checkbox\" checked={this.state.isChecked} onChange={this.handleCheck}/>\r\n </div>\r\n </div>\r\n );\r\n }\r\n}\r\n\r\nconst title = (\r\n <div>\r\n <Txt/>\r\n </div>\r\n\r\n)\r\n```\r\n\r\n注意:\r\n\r\n输入框,富文本框,下拉框都是操作value属性值\r\n\r\n复选框操作checked属性\r\n\r\n### 多表单元素优化\r\n\r\n- 给表单元素添加name属性,名称与state相同\r\n- 根据表单元素类型获取对应值\r\n- 在change事件处理程序中通过 [ name ] 来修改对应的state\r\n\r\n```JavaScript\r\nclass Txt extends React.Component {\r\n state = {\r\n txt: \'\',\r\n content: \'\',\r\n city: \'bj\',\r\n isChecked: false,\r\n }\r\n // 统一的变化函数\r\n handleForm = (e) => {\r\n // 获取当前dom对象\r\n const target = e.target\r\n //根据类型获取值\r\n const value = target.type === \'checkbox\' ? target.checked : target.value\r\n // 获取name\r\n const name = target.name\r\n // 设置属性\r\n this.setState({\r\n [name]: value\r\n })\r\n }\r\n\r\n render() {\r\n return (\r\n <div>\r\n {/*文本框*/}\r\n <div>\r\n <input type=\"text\" name=\"txt\" value={this.state.txt} onChange={this.handleForm}/>\r\n </div>\r\n {/*富文本框*/}\r\n <div>\r\n <textarea name=\"content\" value={this.state.content} onChange={this.handleForm}></textarea>\r\n </div>\r\n {/*下拉框*/}\r\n <div>\r\n <select name=\"city\" value={this.state.city} onChange={this.handleForm}>\r\n <option value=\"sh\">上海</option>\r\n <option value=\"bj\">北京</option>\r\n <option value=\"cd\">成都</option>\r\n <option value=\"cs\">长沙</option>\r\n </select>\r\n </div>\r\n {/*复选框*/}\r\n <div>\r\n <input name=\"isChecked\" type=\"checkbox\" checked={this.state.isChecked} onChange={this.handleForm}/>\r\n </div>\r\n </div>\r\n );\r\n }\r\n}\r\n\r\nconst title = (\r\n <div>\r\n <Txt/>\r\n </div>\r\n\r\n)\r\n```\r\n\r\n### 非受控组件\r\n\r\n- 说明:借助与ref,使用原生DOM方式获取表单元素值\r\n- ref的作用:获取DOM或组件\r\n\r\n\r\n\r\n具体步骤\r\n\r\n1. 调用React.createRef()方法创建一个ref对象\r\n\r\n```JavaScript\r\nthis.txtRef = React.createRef()\r\n```\r\n1. 将创建好的ref对象添加到文本框中\r\n\r\n```JavaScript\r\n<input type=\"text\" ref={this.txtRef}/>\r\n```\r\n1. 通过ref对象获取到文本框的值\r\n\r\n```JavaScript\r\nthis.txtRef.current.value\r\n```\r\n\r\n\r\n\r\n示例:\r\n\r\n```JavaScript\r\nclass NotTxt extends React.Component {\r\n constructor() {\r\n super();\r\n // 创建ref\r\n this.txtRef = React.createRef()\r\n }\r\n\r\n getTxt = () => {\r\n console.log(\'文本框值为:\', this.txtRef.current.value)\r\n }\r\n\r\n render() {\r\n return (\r\n <div>\r\n <input type=\"text\" ref={this.txtRef}/>\r\n <button onClick={this.getTxt}>获取文本框中的值</button>\r\n </div>\r\n )\r\n }\r\n}\r\n```\r\n\r\n\r\n\r\n## 案例:评论列表\r\n\r\n![](http://python.fengfengzhidao.icu/img/20211206143959.png)\r\n\r\n基本结构\r\n\r\n```JavaScript\r\nclass Comment extends React.Component {\r\n render() {\r\n return (\r\n <div className=\"comment\">\r\n {/*评论人*/}\r\n <div>\r\n <input className=\"user\" type=\"text\" placeholder=\"请输入评论人\"/>\r\n </div>\r\n {/*评论内容*/}\r\n <div>\r\n <textarea className=\"comment_content\" rows=\"4\" placeholder=\"请输入评论内容\"></textarea>\r\n </div>\r\n {/*按钮*/}\r\n <div>\r\n <button>提交评论</button>\r\n </div>\r\n {/*评论列表*/}\r\n <div>\r\n <ul>\r\n <li>\r\n <h4>枫枫</h4>\r\n <p>沙发</p>\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nconst title = (\r\n <div>\r\n <Comment/>\r\n </div>\r\n)\r\n```\r\n\r\n### 渲染评论列表\r\n\r\n```JavaScript\r\nstate = {\r\n comment_list: [\r\n {id: 1, name: \'枫枫\', content: \'沙发!\'},\r\n {id: 2, name: \'jack\', content: \'板凳!\'},\r\n {id: 3, name: \'rose\', content: \'楼主好人!\'},\r\n {id: 4, name: \'tom\', content: \'滴~好人卡!\'},\r\n ]\r\n}\r\n\r\n...\r\n<ul>\r\n {this.state.comment_list.map(item => <li key={item.id} >\r\n <h4>{item.name}</h4>\r\n <p>{item.content}</p>\r\n </li>)}\r\n</ul>\r\n\r\n```\r\n\r\n渲染暂无评论\r\n\r\n如果没有评论就显示暂无评论\r\n\r\n- 判断列表长度是否为0\r\n\r\n```JavaScript\r\n{/*根据条件决定要渲染的内容*/}\r\n{\r\n this.state.comment_list.length === 0 ? (\r\n <div className=\"no_comment_list\">暂无评论,快去评论吧!</div>\r\n ) : (\r\n <div>\r\n <ul>\r\n {this.state.comment_list.map(item => <li key={item.id}>\r\n <h4>{item.name}</h4>\r\n <p>{item.content}</p>\r\n </li>)}\r\n </ul>\r\n </div>\r\n )\r\n}\r\n```\r\n\r\n优化:\r\n\r\n将其封装为一个函数\r\n\r\n```JavaScript\r\nrenderList() {\r\n const {comment_list} = this.state\r\n if (comment_list === 0) {\r\n return <div className=\"no_comment_list\">暂无评论,快去评论吧!</div>\r\n }\r\n return (\r\n <div>\r\n <ul>\r\n {comment_list.map(item => <li key={item.id}>\r\n <h4>{item.name}</h4>\r\n <p>{item.content}</p>\r\n </li>)}\r\n </ul>\r\n </div>\r\n )\r\n}\r\n...\r\n\r\n{/*评论列表*/}\r\n{this.renderList()}\r\n\r\n```\r\n\r\n### 获取评论信息\r\n\r\n```JavaScript\r\nstate = {\r\n comment_list: [\r\n {id: 1, name: \'枫枫\', content: \'沙发!\'},\r\n {id: 2, name: \'jack\', content: \'板凳!\'},\r\n {id: 3, name: \'rose\', content: \'楼主好人!\'},\r\n {id: 4, name: \'tom\', content: \'滴~好人卡!\'},\r\n ],\r\n // 评论人\r\n userName: \'\',\r\n // 评论内容\r\n UserComment: \'\',\r\n}\r\n\r\nhandleForm = (e) => {\r\n const {name, value} = e.target\r\n\r\n this.setState({\r\n [name]: value\r\n })\r\n}\r\n\r\nrender() {\r\n\r\n const {userName, UserComment} = this.state\r\n return (\r\n <div className=\"comment\">\r\n {/*评论人*/}\r\n <div>\r\n <input\r\n className=\"user\"\r\n type=\"text\"\r\n value={userName}\r\n name=\"userName\"\r\n onChange={this.handleForm}\r\n placeholder=\"请输入评论人\"/>\r\n </div>\r\n {/*评论内容*/}\r\n <div>\r\n <textarea\r\n className=\"comment_content\"\r\n rows=\"4\" value={UserComment}\r\n name=\"UserComment\"\r\n onChange={this.handleForm}\r\n placeholder=\"请输入评论内容\"></textarea>\r\n </div>\r\n {/*按钮*/}\r\n <div>\r\n <button>提交评论</button>\r\n </div>\r\n {/*评论列表*/}\r\n {this.renderList()}\r\n </div>\r\n )\r\n}\r\n```\r\n\r\n### 发表评论\r\n\r\n```JavaScript\r\n// 发表评论\r\naddComment = (e) => {\r\n const {comment_list, userName, userComment} = this.state\r\n const new_comments = [\r\n {\r\n id: Math.random(),\r\n name: userName,\r\n content: userComment,\r\n }, ...comment_list]\r\n this.setState({\r\n comment_list: new_comments\r\n })\r\n}\r\n\r\n\r\n...\r\n\r\n<button onClick={this.addComment}>提交评论</button>\r\n\r\n```\r\n\r\n优化\r\n\r\n```JavaScript\r\n// 发表评论\r\naddComment = (e) => {\r\n const {comment_list, userName, userComment} = this.state\r\n // 非空校验\r\n if (userName.trim() === \'\' || userComment.trim() === \'\'){\r\n alert(\'请输入内容\')\r\n return\r\n }\r\n const new_comments = [\r\n {\r\n id: Math.random(),\r\n name: userName,\r\n content: userComment,\r\n }, ...comment_list]\r\n this.setState({\r\n comment_list: new_comments,\r\n // 清空输入的内容\r\n userName: \'\',\r\n userComment: \'\'\r\n })\r\n}\r\n```\r\n\r\n# 组件通信\r\n\r\n## 组件的props\r\n\r\n- 作用:接收传递给组件的数据\r\n- 传递数据:给组件添加属性\r\n- 接收数据\r\n\r\n 函数组件使用props接收数据\r\n\r\n```JavaScript\r\n// 接收数据\r\nfunction FunProp(props) {\r\n console.log(props) // {name: \'jack\', age: 19}\r\n return (\r\n <div>接收到数据: {props.name}</div>\r\n )\r\n}\r\n\r\n// 传递数据\r\nconst title = (\r\n <div>\r\n <FunProp name=\"jack\" age={19}/>\r\n </div>\r\n)\r\n```\r\n\r\n 类组件通过this.props接收数据\r\n\r\n```JavaScript\r\nclass ClassProp extends React.Component {\r\n render() {\r\n return (\r\n <div>接收到数据: {this.props.name}, {this.props.age}</div>\r\n )\r\n }\r\n}\r\n\r\nconst title = (\r\n <div>\r\n <ClassProp name=\"jack\" age={19}/>\r\n </div>\r\n)\r\n```\r\n\r\n特点:\r\n\r\n1. 可以给组件传递任意类型的数据(字符串,整数,对象,甚至是函数)\r\n\r\n```JavaScript\r\n<ClassProp\r\n name=\"jack\"\r\n age={19}\r\n colors={[\"red\", \'green\', \'blue\']}\r\n fn={()=>console.log(\'这是一个函数\')}\r\n tag={<p>这是一个p标签</p>}\r\n/>\r\n```\r\n1. props是只读对象,只能读取属性的值,不能修改属性的值\r\n2. 在使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数中获取到props!\r\n\r\n```JavaScript\r\nconstructor(props) {\r\n super(props);\r\n}\r\n```\r\n\r\n 在写`constructor`的时候,推荐将props传递给super\r\n\r\n## 组件通信的三种方式\r\n\r\n1. 父组件 → 子组件\r\n2. 子组件 → 父组件\r\n3. 兄弟组件\r\n\r\n### 父传子\r\n\r\n1. 父组件提供要传递的state数据\r\n2. 给子组件标签添加属性,值为state中的数据\r\n3. 子组件中通过props接收父组件中传递的数据\r\n\r\n```JavaScript\r\n// 子组件\r\nclass Child extends React.Component {\r\n render() {\r\n return (\r\n <div>\r\n 我是一个子组件,这是父组件的值:{this.props.name}\r\n </div>\r\n )\r\n }\r\n}\r\n// 父组件\r\nclass Parent extends React.Component {\r\n state = {\r\n lastName: \'王\'\r\n }\r\n render() {\r\n return (\r\n <div>\r\n <Child name={this.state.lastName}/>\r\n </div>\r\n )\r\n }\r\n}\r\nconst title = (\r\n <div>\r\n <Parent/>\r\n </div>\r\n)\r\n```\r\n\r\n### 子传父\r\n\r\n思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数\r\n\r\n1. \r\n\r\n\r\n\r\n```JavaScript\r\nconst Child = (props) => {\r\n function handleClick() {\r\n // 调用父组件传递来的回调函数\r\n props.getMsg(\'子组件的数据\')\r\n }\r\n\r\n return (\r\n <div>\r\n 我是一个子组件\r\n <button onClick={handleClick}>点我,给父组件发送数据</button>\r\n </div>\r\n )\r\n}\r\n\r\nconst Parent = () => {\r\n // 给子组件传递一个回调函数,由子组件调用\r\n function getMsg(msg) {\r\n console.log(\'接收到子组件的数据\')\r\n }\r\n\r\n return (\r\n <div>\r\n <Child getMsg={getMsg}/>\r\n </div>\r\n )\r\n}\r\n\r\n```\r\n\r\n如果要将子组件传给父组件的数据展示在页面中,只能通过类组件去设置一个属性\r\n\r\n注意:回调函数this指向问题\r\n\r\n### 兄弟组件\r\n\r\n- 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态\r\n- 思想:状态提升\r\n- 公共父组件职责:1. 提供共享状态 2. 提供操作共享状态的方法\r\n- 要通讯的子组件只需要通过props接收状态和操作状态的方法\r\n\r\n\r\n\r\n```JavaScript\r\n// 父组件\r\nclass Counter extends React.Component {\r\n // 在父组件中提供共享状态\r\n state = {\r\n count: 0\r\n }\r\n // 提供修改状态的方法\r\n onSetCount = () => {\r\n this.setState({\r\n count: this.state.count + 1\r\n })\r\n }\r\n\r\n render() {\r\n return (\r\n <div>\r\n {/*将状态传递给子组件*/}\r\n <Child1 count={this.state.count}/>\r\n {/*将修改状态的方法传递给子组件*/}\r\n <Child2 setCount={this.onSetCount}/>\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nconst Child1 = (props) => {\r\n // 接收父组件传递的数据,展示在页面上\r\n return <h2>计数器:{props.count}</h2>\r\n}\r\n\r\nconst Child2 = (props) => {\r\n // 子组件调用父组件传来的方法\r\n return <button onClick={() => props.setCount()}> +1</button>\r\n}\r\n\r\nconst title = (\r\n <Counter/>\r\n)\r\n```\r\n\r\n### context的基本使用\r\n\r\n多层嵌套的组件关系,如何传递呢?\r\n\r\n原来:使用props一层一层组件向下传递\r\n\r\n![](http://python.fengfengzhidao.icu/img/20211206163943.png)\r\n\r\n作用:跨组件传递数据(例如:主题,语言)\r\n\r\n使用步骤:\r\n\r\n1. 调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件\r\n2. 使用Provider组件作为父节点\r\n3. 设置value属性,表示要传递的数据\r\n\r\n```JavaScript\r\n<Provider value=\"pink\">\r\n ...\r\n</Provider>\r\n```\r\n1. 调用Consumer组件接收数据\r\n\r\n```JavaScript\r\n{/*在Consumer组件中接收Provider传递来的数据*/}\r\n<Consumer>\r\n {\r\n data => <span>我是span -- {data}</span>\r\n }\r\n</Consumer>\r\n\r\n```\r\n\r\n\r\n\r\n```JavaScript\r\n// 创建context\r\n\r\nconst {Provider, Consumer} = React.createContext()\r\n\r\n\r\n// 最外层的组件\r\nclass App extends React.Component {\r\n render() {\r\n return (\r\n // 使用Provider作为父组件\r\n <Provider value=\"pink\">\r\n <div className=\"app\">\r\n <Node/>\r\n </div>\r\n </Provider>\r\n\r\n\r\n )\r\n }\r\n}\r\n\r\nconst Node = () => {\r\n return (\r\n <div className=\"node\">\r\n <SubNode/>\r\n </div>\r\n )\r\n}\r\n\r\nconst SubNode = () => {\r\n return (\r\n <div className=\"subNode\">\r\n <Child/>\r\n </div>\r\n )\r\n}\r\n// 最里层的组件\r\nconst Child = () => {\r\n return (\r\n <div className=\"child\">\r\n <div>\r\n {/*在Consumer组件中接收Provider传递来的数据*/}\r\n <Consumer>\r\n {\r\n data => <span>我是span -- {data}</span>\r\n }\r\n </Consumer>\r\n </div>\r\n </div>)\r\n\r\n}\r\n\r\nconst title = (\r\n <App/>\r\n)\r\n```\r\n\r\n## props深入\r\n\r\n### children属性\r\n\r\n- children属性:表示组件标签的子节点。当组件标签有子节点时,props就会有该属性\r\n- 与props属性一样,它的值可以是任意的数据类型,函数,甚至是jsx\r\n\r\n```JavaScript\r\nconst App = props => {\r\n return (\r\n <div>\r\n <h1>组件标签的子节点:</h1>\r\n <p>{props.children}</p>\r\n </div>\r\n )\r\n}\r\n\r\nconst title = (\r\n // 会将我是子节点传递给props.children\r\n <App>我是子节点</App>\r\n)\r\n```\r\n\r\nchildren也可以是jsx\r\n\r\n```JavaScript\r\nconst Test = () => <button> 我是button组件 </button>\r\n\r\n\r\nconst App = props => {\r\n return (\r\n <div>\r\n <h1>组件标签的子节点:</h1>\r\n <p>{props.children}</p>\r\n </div>\r\n )\r\n}\r\n\r\nconst title = (\r\n // 会将我是子节点传递给props.children\r\n <App>\r\n {/*<p>我是子组件</p>*/}\r\n <Test/>\r\n </App>\r\n)\r\n```\r\n\r\n### props校验\r\n\r\n- 组件传递的时候,可以规定传入的数据类型\r\n- 如果不是规定的数据类型,那么就抛出对应的异常\r\n\r\n```JavaScript\r\nnpm i prop-types\r\n```\r\n\r\n使用\r\n\r\n```JavaScript\r\nimport PropTypes from \'prop-types\'\r\n\r\nfunction App(props) {\r\n return (\r\n <div>Hi, {props.colors}</div>\r\n )\r\n}\r\n\r\n// 添加props校验\r\nApp.propTypes = {\r\n colors: PropTypes.array,\r\n}\r\n\r\nconst title = (\r\n <div>\r\n <App colors=\"red\"/>\r\n <App colors={[\'red\', \'blue\']}/>\r\n </div>\r\n\r\n)\r\n\r\n```\r\n\r\n![](http://python.fengfengzhidao.icu/img/20211206172216.png)\r\n\r\n#### 约束规则\r\n\r\n1. 常见类型:array,bool,func,number,object,string\r\n2. React元素类型:element\r\n3. 必填项:isRequired\r\n4. 特定结构的对象 .shape( { } )\r\n\r\n### props的默认值','2022-02-10 10:21:28.651876','2022-03-10 22:50:05.175941',1,1,51,0,1,0,1,'枫枫','枫枫知道个人博客',6,NULL,NULL,24965),(34,'部署你的Django项目【命令行版本】','部署django项目(命令行版本)\n如果有条件,建议使用宝塔,傻瓜式操作,使用纯命令部署相对来说比较复杂\n本机准备工作\n确保你的项目没有问题之后,将DEBUG模式改为FALSE\n导','## 部署django项目(命令行版本)\n\n如果有条件,建议使用宝塔,傻瓜式操作,使用纯命令部署相对来说比较复杂\n\n## 本机准备工作\n\n确保你的项目没有问题之后,将DEBUG模式改为FALSE\n\n### 导出第三方模块\n\n执行\n\n```Bash\npip freeze > requirements.txt\n```\n\n它会导出一个文件,这个文件会记录你用了哪些第三方模块\n\n### 导出数据库\n\n这个是针对使用MySQL而言\n\n```Bash\nmysqldump -u root -p pro_blog > pro_blog.sql\n```\n\n这样你就可以将你的项目进行打包了,虚拟环境可以删掉了\n\n![](http://python.fengfengzhidao.icu/img/20211030211122.png)\n\n文件里面只需要这几项,media是关于用户上传的\n\n\n\n\n\n## 上线部署\n\n准备好和开发环境一样的python版本,创建一个虚拟环境,导入这些第三方模块\n\n```Bash\n# 安装虚拟环境的第三方包 virtualenv\npip install virtualenv\n\n# 创建虚拟环境(虚拟环境一般放在项目根目录下)\nvirtualenv env_name\n\n# 激活虚拟环境\nsource env_name/bin/activate\n\n# 退出虚拟环境\ndeactivate\n\n```\n\n\n\n在虚拟环境中导入requirements中的第三方模块\n\n```Bash\npip install -r requirements.txt\n```\n\n\n\n导入数据库\n\n```Bash\n# 在服务器中创建一个数据库\ncreate database blog\n\n# 导入数据\nsource pro_blog.sql\n\n```\n\n\n\n### 收集静态资源\n\n在django中,如果DEBUG=TRUE,那么django会帮我们完成静态资源的分发\n\n但是,实际项目上线,我们不需要django为我们进行静态资源分发\n\n我们使用nginx做静态文件转发\n\n在django的配置文件中,加上\n\n```Bash\nSTATIC_URL = \'/static/\'\nSTATICFILES_DIRS = [\n os.path.join(BASE_DIR, \'static\')\n]\nSTATIC_ROOT = os.path.join(BASE_DIR, \'feng_static\')\n```\n\n主要是STATIC_ROOT ,然后进行静态文件收集,django就会为我们收集所有的静态文件\n\n```Bash\npython manage.py collectstatic\n```\n\n\n\n启动django程序\n\n```Bash\npython manage.py runserver 0.0.0.0:8000\n```\n\n顺便去你主机的8000端口去看看有没有报错,虽然静态文件没有加载,但是数据肯定有\n\n\n\n## 安装uwsgi\n\n```Bash\npip install uwsgi\n```\n\n在我们通过Django创建django项目时,在子目录app01下已经帮我们生成的 wsgi.py文件。所以,我们只需要再创建blog.ini配置文件即可,当然,uwsgi支持多种类型的配置文件,如xml,ini等。此处,使用ini类型的配置。\n\n```Ini\n# myweb_uwsgi.ini file\n[uwsgi]\n\n# Django-related settings\n\nsocket = :8000\n\n# the base directory (full path), 你项目的根目录的位置\nchdir = /home/fnngj/pydj/myweb\n\n# Django s wsgi file ,你wsgi的位置\nmodule = myweb.wsgi\n\n# process-related settings\n# master\nmaster = true\n\n# maximum number of worker processes\nprocesses = 4\n\n# ... with appropriate permissions - may be needed\n# chmod-socket = 664\n# clear environment on exit\nvacuum = true\n```\n\n运行\n\n```Ini\nuwsgi --ini myweb_uwsgi.ini \n```\n\n\n\n注意查看uwsgi的启动信息,如果有错,就要检查配置文件的参数是否设置有误。\n\n\n\n## nginx配置\n\n再接下来要做的就是修改nginx.conf配置文件。打开/etc/nginx/nginx.conf文件,添加如下内容。 \n\n\n\nnginx做静态文件转发\n\n```nginx\n# nginx配置\n\nserver {\n listen 80;\n server_name _;\n location / {\n uwsgi_pass 0.0.0.0:8000; # uwsgi运行的端口\n include uwsgi_params;\n }\n location /static{\n alias /www/wwwroot/feng_blog/feng_static; # 你收集的静态文件的位置\n }\n}\n\n```\n\n重启一下nginx,去访问客户机的ip,正常加载说明成功!','2022-02-13 05:58:06.965138','2022-03-10 22:50:05.173939',1,1,74,0,66,1,2,'枫枫','枫枫知道个人博客',9,NULL,NULL,2377),(35,'Vue项目部署【前后端分离部署】','前后端分离项目部署\n前后端项目分别开发完成之后,我们可以选择两种部署方式,第一种就是将前端生成的文件放到后端中,由后端去部署,今天我们只讲第二种方式\n前端部署\n项目打包\nBash','# 前后端分离项目部署\n\n前后端项目分别开发完成之后,我们可以选择两种部署方式,第一种就是将前端生成的文件放到后端中,由后端去部署,今天我们只讲第二种方式\n\n## 前端部署\n\n项目打包\n\n```Bash\nnpm run build\n```\n\n将生成的dist文件放到要部署的文件夹,我这里是`www/wwwroot/fengfeng/`下面\n\n![](http://python.fengfengzhidao.com/1031/20211128212437.png)\n\n接下来做nginx的配置,这样我们就可以通过访问端口去访问前端项目了\n\nnginx配置\n\n```nginx\nserver {\n listen 80;\n server_name localhost;\n \n location /api/ {\n rewrite ^/(api/.*) /$1 break;\n proxy_pass http://192.168.227.130:8080/api/; # 后端nginx的服务器地址\n }\n location / {\n try_files $uri $uri/ /index.html; # 解决刷新404问题\n root /www/wwwroot/index.com/dist/;\n index index.html index.htm;\n }\n \n error_page 500 502 503 504 /50x.html;\n location = /50x.html {\n root html;\n }\n}\n```\n\n主要是有几个点要注意\n\n- 路由刷新404问题,使用`try_files `\n- 请求后端接口,使用`proxy_pass `\n\n大家可参考我的代码示例\n\n### 多域名部署\n\n如果要做多域名代理,先去etc下面找到hosts文件,将你的域名做一个映射\n\n![](http://python.fengfengzhidao.com/1031/20211128212900.png)\n\n```Bash\n127.0.0.1 www.fengfengzhidao.com\n127.0.0.1 yyds.fengfengzhidao.com\n```\n\nnginx\n\n```nginx\nserver {\n listen 80;\n server_name yyds.fengfengzhidao.com; # 写你的域名\n \n location /api/ {\n rewrite ^/(api/.*) /$1 break;\n proxy_pass http://ip:port; # 后端nginx的服务器地址\n }\n location / {\n try_files $uri $uri/ /index.html; # 解决刷新404问题\n root /www/wwwroot/fengfeng/dist/;\n index index.html index.htm;\n } \n}\n```\n\n配置完成之后重启nginx服务器,去访问你的域名,应该是可以看到效果的,至少网页的标题是加载出来了,现在需要去部署后端,这样前端才能正常请求数据\n\n## 后端配置\n\nsettings\n\n```Python\nSTATIC_URL = \'/static/\'\nSTATICFILES_DIRS = [\n os.path.join(BASE_DIR, \'static\')\n]\nSTATIC_ROOT = os.path.join(BASE_DIR, \'feng_static\')\n```\n\n收集静态资源\n\n```Python\npython manage.py collectstatic\n```\n\n如果你的项目完全没有使用静态文件,那么这一步你可以不用管\n\n接下来导出所用第三方模块和数据库\n\n```Bash\n# 导出第三方模块\npip freeze > requirements.txt\n\n# 导出数据库\nmysqldump -u root -p pro > pro.sql\n\n```\n\n\n\n![](http://python.fengfengzhidao.com/1031/20211128213823.png)\n\n那个第三方模块可能会有个别下载不成功,大家可以去那个模块那里看看有没有少了哪个模块\n\n基本上到这一步就差不多了,接下来去配置nginx代理后端服务\n\nnginx\n\n```nginx\nserver {\n listen 8080; # 监听端口\n server_name _; # 服务名字,多域名就写域名\n location / {\n uwsgi_pass 0.0.0.0:8080; # django运行的端口\n include uwsgi_params; # 固定搭配\n }\n location /static{\n alias /www/wwwroot/blog_back/feng_static; # 你收集的静态文件的位置\n }\n}\n\n```\n\n这样你的项目就部署成功了!\n\n![](http://python.fengfengzhidao.com/1031/20211128214013.png)','2022-02-13 06:03:12.480842','2022-03-10 22:50:05.171936',1,1,49,0,1,3,3,'枫枫','枫枫知道个人博客',10,'qwert',NULL,2398),(36,'python第三方模块--pendulum','妈妈咋也不用担心我不会处理时间了\npendulum介绍\n但是,Python 中的时间处理,搞得我怀疑人生,总是弄不清该用 time 还是 datetime,什么时间戳、时间运算、各','妈妈咋也不用担心我不会处理时间了\n\n\n\n## pendulum介绍\n\n但是,Python 中的时间处理,搞得我怀疑人生,总是弄不清该用 time 还是 datetime,什么时间戳、时间运算、各种格式的时间转化,概念多,操作复杂,bug 还得找半天,实在是太麻烦了,一遇到时间处理就焦虑~\n\n今天给大家介绍一个处理时间的神器 —— Pendulum,跟过去说拜拜,让你用 Python 处理时间快步如飞,还等啥,来吧!\n\n这是个第三方模块,需要进行pip安装\n\n```Bash\npip install pendulum\n```\n\n## 时间的基本获取\n\n```Python\nimport pendulum\n\nd1 = pendulum.yesterday() # 昨天\n# 2021-10-02T00:00:00+08:00\n\nd2 = pendulum.today() # 今天\n# 2021-10-03T00:00:00+08:00\n\nd3 = pendulum.tomorrow() # 明天\n# 2021-10-04T00:00:00+08:00\n\nd2.diff(d1).in_days() # 相差多少天\n# 1\n\nd2.diff(d1).in_hours() # 相差多少小时\n# 24\n\npendulum.now() # 现在的时间\n```\n\n是不是感觉很有亲和力,各种操作都符合人性化。\n\n而且将 datetime 和 time 两个库合并了,再也不用纠结应该用哪个了。\n\n下面浏览一下 Pendulum 的更大威力吧。\n\n## 搞定时区\n\n时区处理是比较麻烦地事情,还好我们只使用一个时区,省去了很多麻烦。\n\n不过时区的概念需要了解,再说,谁能说得准,不开发国际化程序呢。\n\n一起困难,Pendulum 让我们优雅处之。\n\n看例子:\n\n```Python\nimport pendulum\n\ndt1 = pendulum.datetime(2021, 10, 3)\nprint(dt2.timezone.name) # UTC\n\ndt2 = pendulum.datetime(2021, 10, 3, tz=\"Asia/Shanghai\")\n\nprint(dt2.timezone.name) # Asia/Shanghai\n```\n\n- 不指定,就是默认的 UTC 0 时区\n- 创建时间对象时可以指定时区,例如我们的时区名称是 `Asia/Shanghai`\n- 通过 `timezone.name` 属性,可查看时间对象的具体时区,或者直接用 `timezone_name` 直接获取,另外,属性 `timezone` 可以简写成 `tz`\n\n> Pendulum 时区只支持用 **时区名称** 设置时区\n\n### 时区运算\n\n```Python\nimport pendulum\n\nfirst = pendulum.datetime(2012, 9, 5, 23, 26, 11, 0, tz=\'America/Toronto\')\nsecond = pendulum.datetime(2012, 9, 5, 20, 26, 11, 0, tz=\'America/Vancouver\')\n\nfirst.to_datetime_string()\n# 2012-09-05 23:26:11\n\nfirst.timezone_name\n# America/Toronto\nsecond.to_datetime_string()\n# 2012-09-05 20:26:11\nsecond.timezone_name\n# America/Vancouver\n\nfirst == second\n# True\nfirst != second\n# False\nfirst > second\n# False\nfirst < second\n# False\n\nfirst = first.on(2012, 1, 1).at(0, 0, 0)\nsecond = second.on(2012, 1, 1).at(0, 0, 0)\n# tz is still America/Vancouver for second\n\nfirst == second\n# False\nfirst != second\n# True\nfirst > second\n# False\nfirst < second\n# True\n\nsecond.diff(first).in_hours()\n# 3\n```\n\n- 时区 `America/Toronto` 和 `America/Vancouver` 相差 3 小时\n- 设置相差 3 小时的时间,两者是相等的\n- 设置完全相同的时间,比较时是不相等的,计算它们之间的差异,可以看到相差 3 小时\n- `diff` 方法用于与另一个时间对象比较,`in_hours` 方法是时间区间的方法,可以将区间转化为小时,同理还有 `in_days`、`in_years` 等\n\n## 时间运算\n\n时间运算包括**比较**、**计算差异** 和 **增减**。上面例子中已经计算了不同时区的时间差异,下面我们详细的说一下。\n\n### 比较\n\n比较很简单,对两个时间对象做比较就可以了,支持 `==`、`!=`、`>`、`>=`、`<`、`<=`,比较的结果是 `True` 或 `False`\n\n### 计算差异\n\n前面时区的例子里已经看到了,使用 `diff` 方法来计算差异,会返回一个时间区间(`Period`)对象\n使用 `diff` 时,如果不提供比较参加,就会默认和当前时间比较。\n\n```Python\nimport pendulum\n\nfirst = pendulum.datetime(2012, 1, 31, 0)\nsecond = pendulum.datetime(2012, 2, 1, 0)\nfirst.diff(second)\n# <Period [2012-01-31T00:00:00+00:00 -> 2012-02-01T00:00:00+00:00]>\n\nfirst.diff()\n# <Period [2012-01-31T00:00:00+00:00 -> 2021-10-04T04:44:56.337989+00:00]>\n```\n\n对于时间区间(`period`)来说,处理前面提到的 `in_days` 等方法,将区间转化为一个单位的数量,还可以直接使用对应的属性,例如 `days`、`years`、`weeks` 等,效果是一样的。\n\n### 增减\n\n如果要的时间增加或者减少某些时间,可以使用 `add` 和 `subtract` 方法:\n\n```Python\nimport pendulum\n\ndt = pendulum.datetime(2012, 1, 31)\n\ndt = dt.add(years=5)\n# \'2017-01-31 00:00:00\'\ndt = dt.add(years=1)\n# \'2018-01-31 00:00:00\'\ndt = dt.subtract(years=1)\n# \'2017-01-31 00:00:00\'\ndt = dt.subtract(years=5)\n# \'2012-01-31 00:00:00\'\n\ndt = dt.add(months=60)\n# \'2017-01-31 00:00:00\'\ndt = dt.add(months=1)\n# \'2017-02-28 00:00:00\'\ndt = dt.subtract(months=1)\n# \'2017-01-28 00:00:00\'\ndt = dt.subtract(months=60)\n# \'2012-01-28 00:00:00\'\n\ndt = dt.add(days=29)\n# \'2012-02-26 00:00:00\'\ndt = dt.add(days=1)\n# \'2012-02-27 00:00:00\'\ndt = dt.subtract(days=1)\n# \'2012-02-26 00:00:00\'\ndt = dt.subtract(days=29)\n# \'2012-01-28 00:00:00\'\n\ndt = dt.add(weeks=3)\n# \'2012-02-18 00:00:00\'\ndt = dt.add(weeks=1)\n# \'2012-02-25 00:00:00\'\ndt = dt.subtract(weeks=1)\n# \'2012-02-18 00:00:00\'\ndt = dt.subtract(weeks=3)\n# \'2012-01-28 00:00:00\'\n\ndt = dt.add(hours=24)\n# \'2012-01-29 00:00:00\'\ndt = dt.add(hours=1)\n# \'2012-02-25 01:00:00\'\ndt = dt.subtract(hours=1)\n# \'2012-02-29 00:00:00\'\ndt = dt.subtract(hours=24)\n# \'2012-01-28 00:00:00\'\n\ndt = dt.add(minutes=61)\n# \'2012-01-28 01:01:00\'\ndt = dt.add(minutes=1)\n# \'2012-01-28 01:02:00\'\ndt = dt.subtract(minutes=1)\n# \'2012-01-28 01:01:00\'\ndt = dt.subtract(minutes=24)\n# \'2012-01-28 00:00:00\'\n\ndt = dt.add(seconds=61)\n# \'2012-01-28 00:01:01\'\ndt = dt.add(seconds=1)\n# \'2012-01-28 00:01:02\'\ndt = dt.subtract(seconds=1)\n# \'2012-01-28 00:01:01\'\ndt = dt.subtract(seconds=61)\n# \'2012-01-28 00:00:00\'\n\ndt = dt.add(years=3, months=2, days=6, hours=12, minutes=31, seconds=43)\n# \'2015-04-03 12:31:43\'\ndt = dt.subtract(years=3, months=2, days=6, hours=12, minutes=31, seconds=43)\n# \'2012-01-28 00:00:00\'\n```\n\n- `add` 和 `subtract` 方法参数一致,支持 `years`、`months`、`weeks` 等多种时间单位,而且可以一起设置\n- 时间单位参数可以支持负数,相当于 `add` 和 `subtract` 可以相互替换\n- 时间单位参数还支持小数,比如加上一天半可以写成 `dt.add(days=1.5)`\n\n## 时间调整\n\n时间调整很有用,很多时候我们需要计算下一个周一,当时只能通过日期 API 摸,当时要是知道 `Pendulum` 就省事多了:\n\n```Python\nimport pendulum\n\ndt = pendulum.datetime(2012, 1, 31, 12, 0, 0)\n\ndt.start_of(\'day\')\n# \'2012-01-31 00:00:00\'\n\ndt.end_of(\'day\')\n# \'2012-01-31 23:59:59\'\n\ndt.start_of(\'month\')\n# \'2012-01-01 00:00:00\'\n\ndt.end_of(\'month\')\n# \'2012-01-31 23:59:59\'\n\ndt.start_of(\'year\')\n# \'2012-01-01 00:00:00\'\n\ndt.end_of(\'year\')\n# \'2012-12-31 23:59:59\'\n\ndt.start_of(\'decade\')\n# \'2010-01-01 00:00:00\'\n\ndt.end_of(\'decade\')\n# \'2019-12-31 23:59:59\'\n\ndt.start_of(\'century\')\n# \'2000-01-01 00:00:00\'\n\ndt.end_of(\'century\')\n# \'2099-12-31 23:59:59\'\n\ndt.start_of(\'week\')\n# \'2012-01-30 00:00:00\'\ndt.day_of_week == pendulum.MONDAY\n# True # ISO8601 week starts on Monday\n\ndt.end_of(\'week\')\n# \'2012-02-05 23:59:59\'\ndt.day_of_week == pendulum.SUNDAY\n# True # ISO8601 week ends on SUNDAY\n\ndt.next(pendulum.WEDNESDAY)\n# \'2012-02-01 00:00:00\'\ndt.day_of_week == pendulum.WEDNESDAY\n# True\n\ndt = pendulum.datetime(2012, 1, 1, 12, 0, 0)\ndt.next()\n# \'2012-01-08 00:00:00\'\ndt.next(keep_time=True)\n# \'2012-01-08T12:00:00+00:00\'\n\ndt = pendulum.datetime(2012, 1, 31, 12, 0, 0)\ndt.previous(pendulum.WEDNESDAY)\n# \'2012-01-25 00:00:00\'\ndt.day_of_week == pendulum.WEDNESDAY\n# True\n\ndt = pendulum.datetime(2012, 1, 1, 12, 0, 0)\ndt.previous()\n# \'2011-12-25 00:00:00\'\ndt.previous(keep_time=True)\n# \'2011-12-25 12:00:00\'\n\nstart = pendulum.datetime(2014, 1, 1)\nend = pendulum.datetime(2014, 1, 30)\nstart.average(end)\n# \'2014-01-15 12:00:00\'\n\n# others that are defined that are similar\n# and tha accept month, quarter and year units\n# first_of(), last_of(), nth_of()\n```\n\n是否看眼花了,我看到这里,兴奋地都要跳起来了,简直是只有没想到的,没有它没实现的呀!\n\n- `start_of` 方法用于计算某个起始时间,可以是 天、年、月、周,甚至可以是世纪。`end_of` 是类似的,用于计算结束\n- `next` 方法用于计算以一个星期,不加参数就是计算下个星期的今天,也可以指定计算下一个哪天,比如下个星期一:`dt.next(pendulum.MONDAY)`。`previous` 是类似的,用于计算向前的天\n- `average` 方法用于计算两个时间的中间时间,简直太方便了\n\n## 时间转字符串\n\n时间对象是一个复杂的对象,对于我们来说不方便看和读,就需要将起转化为字符串,或者将字符串表示的时间转化为时间对象。\n\n`Pendulum` 提供和很多方便的方式:\n\n```Python\nimport pendulum\n\ndt = pendulum.datetime(1975, 12, 25, 14, 15, 16)\nprint(dt)\n# \'1975-12-25T14:15:16+00:00\'\n\ndt.to_date_string()\n# \'1975-12-25\'\n\ndt.to_formatted_date_string()\n# \'Dec 25, 1975\'\n\ndt.to_time_string()\n# \'14:15:16\'\n\ndt.to_datetime_string()\n# \'1975-12-25 14:15:16\'\n\ndt.to_day_datetime_string()\n\'Thu, Dec 25, 1975 2:15 PM\'\n\n# You can also use the format() method\ndt.format(\'dddd Do [of] MMMM YYYY HH:mm:ss A\')\n\'Thursday 25th of December 1975 02:15:16 PM\'\n\n# Of course, the strftime method is still available\ndt.strftime(\'%A %-d%t of %B %Y %I:%M:%S %p\')\n\'Thursday 25th of December 1975 02:15:16 PM\'\n```\n\n- `to_date_string` 转化日期\n\n- `to_datetime_string` 转化日期和时间\n\n- `to_time_string` 转化时间\n- `to_formatted_date_string` 转化为英文书写形式\n\n- `format` 安装指定格式转化\n\n- `strftime` 同 `datetime` 的格式化方法\n\n## 字符串转时间\n\n时间转化字符串,如何将字符串转化为时间类型呢?\n使用 `parse` 方法就好了,看下例子:\n\n```Python\nimport pendulum\n\ndt = pendulum.parse(\'1975-05-21T22:00:00\')\nprint(dt)\n# \'1975-05-21T22:00:00+00:00\n\n# You can pass a tz keyword to specify the timezone\ndt = pendulum.parse(\'1975-05-21T22:00:00\', tz=\'Europe/Paris\')\nprint(dt)\n# \'1975-05-21T22:00:00+01:00\'\n\n# Not ISO 8601 compliant but common\ndt = pendulum.parse(\'1975-05-21 22:00:00\')\n\ndt = pendulum.parse(\'31-01-01\', strict=False)\n\ndt = pendulum.parse(\'31/01/01\', strict=False)\n\ndt = pendulum.parse(\'31/1/1\', strict=False)\n```\n\n- 可以直接转化,也可以在转化时指定时区\n\n- 支持多种时间格式,如果不是标准的时间格式,需要添加参数 `strict=False`,这样 `Pendulum` 就会尽最大可能去猜\n\n## 人性化\n\n现在看到 Pendulum 的强大了吧,不过还有个令人叫绝的功能,就是人性化时间。\n\n如果你注意搜索引擎的结果的话,就能看到,很多时间被表示为:1天前,2周后等等,如果让我们来实现,可得好好想想,如果需求说,搞个英文版的,我们可能有拿起键盘去砸的冲动。\n\n现在好了,直接看例子:\n\n```Python\nimport pendulum\n\npendulum.now().subtract(days=1).diff_for_humans()\n# \'1 day ago\'\n\npendulum.now().diff_for_humans(pendulum.now().subtract(years=1))\n# \'1 year after\'\n\ndt = pendulum.datetime(2011, 8, 1)\ndt.diff_for_humans(dt.add(months=1))\n# \'1 month before\'\ndt.diff_for_humans(dt.subtract(months=1))\n# \'1 month after\'\n\npendulum.now().add(seconds=5).diff_for_humans()\n# \'5 seconds from now\'\n\npendulum.now().subtract(days=24).diff_for_humans()\n# \'3 weeks ago\'\n\npendulum.now().subtract(days=24).diff_for_humans(absolute=True)\n# \'3 weeks\'\n\npendulum.set_locale(\'zh\')\npendulum.now().subtract(days=24).diff_for_humans()\n# \'3周前\'\n\npendulum.now().add(seconds=5).diff_for_humans()\n# \'5秒钟后\'\n\noneday = pendulum.now().diff(pendulum.now().add(days=1))\noneday.in_words()\n# \'1天\'\n```\n\n- `diff_for_humans` 可以将时间区间直接输出成人性化时间\n\n- 参数 `absolute` 的作用是给出一个人性化的时间间隔,而不是相对于现在的说法\n\n- 默认情况下输出的是英语写法,如果要让说中文,通过 `pendulum.set_locale(\'zh\')` 就可以了,厉害吧\n\n- 对于一个时间区域来说,可以用 `in_words` 来输出人性化时间\n\n> 这里注意,对于 `dt.diff_for_humans(dt.subtract(months=1))` 这样的,相对一个日期的时间差异人性化输出,不支持中文,会报错,所以建议先计算出两个日期的差异,再用 `in_words` 做人性化输出,如果有必要,在其后加上`前` 或 `后`。希望这个 bug 能早日修复\n\n## 总结\n\n今天简单介绍了一下 Pendulum 库在时间上的优秀能力,除了这些它还有更多的功能可供发掘。只要多研究,多用,一定能解决你遇到时间处理的问题。\n\n最好的学就是用,所以要不断地通过练习或者实践去用,期望通过这篇介绍,能让你在时间处理上更高效,比心!','2022-02-23 16:30:15.379744','2022-03-10 22:50:05.167933',1,1,84,0,3,1,2,'枫枫','枫枫知道个人博客',14,NULL,NULL,9387),(43,'admin自定义显示','显示字段\n列表页面,显示的是__str__中的字段,如果我需要显示其他的字段,我需要写一个类,在这个类中去编写代码\n```Python class SrcUrlAdmin(admi','## 显示字段\n\n![](http://python.fengfengzhidao.icu/img/20211018093809.png)\n\n列表页面,显示的是__str__中的字段,如果我需要显示其他的字段,我需要写一个类,在这个类中去编写代码\n\n```Python\nclass SrcUrlAdmin(admin.ModelAdmin):\n list_display = [\'href\', \'title\', \'company\', \'create_time\']\n\n\nadmin.site.register(SrcUrl, SrcUrlAdmin)\n```\n\n第一个字段,django会自动给你链接到修改记录的位置\n\n![](http://python.fengfengzhidao.icu/img/20211018094319.png)\n\n后续的很多操作都是基于这个类去操作\n\n\n\n修改站点标题和title\n\n```Python\nadmin.site.site_header = \'SRC资源管理系统\' # 登录框的文字\nadmin.site.site_title = \'枫枫知道SRC资源管理系统\' # 浏览器头部信息\n```\n\n\n\n新增一些字段\n\n```Python\ndomain_num = models.IntegerField(verbose_name=\'子域名数\', default=0)\n status_choice = (\n (0, \'未扫描\'),\n (1, \'已扫描\'),\n (2, \'扫描异常\'),\n )\n status = models.IntegerField(verbose_name=\'是否扫描子域名\', choices=status_choice, default=0)\n\n```\n\n## 显示自定义字段\n\n在`list_display `中可以存放函数,函数的返回值就是每一列显示的内容\n\n![](http://python.fengfengzhidao.icu/img/20211018134750.png)\n\n```Python\ndef field_color(self):\n # self 每一行的记录\n # print(self.status)\n # print(self.get_status_display()) # 获取choice中的显示字段\n if self.status:\n # 一定要使用 make_safe进行转换\n return mark_safe(fr\'<span style=\"color: green\">{self.get_status_display()}</span>\')\n return mark_safe(fr\'<span style=\"color: red\">{self.get_status_display()}</span>\')\n\nfield_color.short_description = \'状态\' # 自定义字段标题\nlist_display = [\'href\', ... , field_color, \'create_time\']\n```\n\nmodel中choice参数介绍\n\n```Python\nclass SrcUrl(models.Model):\n ...\n domain_num = models.IntegerField(verbose_name=\'子域名数\', default=0)\n status_choice = (\n (0, \'未扫描\'),\n (1, \'已扫描\')\n )\n status = models.IntegerField(verbose_name=\'是否扫描子域名\', choices=status_choice, default=0)\n ...\n\n```\n\n适用于int,char类型字段,并且在后台中是动态显示的\n\n![](http://python.fengfengzhidao.icu/img/20211018135452.png)\n\nstatus_choice 里的每一个元组,前端渲染就是每一个选项,元组里面的第一个元素就是最终的值(实际存储),第二个元素,是显示的内容,\n\n```Python\nprint(self.status) # 实际内容\nprint(self.get_status_display()) # 显示内容\n```\n\n重点\n\n> make_safe将html转换为安全字符\nshort_description 列标题\nlist_display 中放函数名\n\n## 排序,过滤,搜索\n\n```Python\nordering = [\'title\'] # 按照title升序 -title 降序\nlist_filter = [\'create_time\'] # 按照时间可过滤\nsearch_fields = [\'title\', \'href\'] # 可以搜索的字段\ndate_hierarchy = \'create_time\' # 时间导航栏\n\n```\n\n![](http://python.fengfengzhidao.icu/img/20211018140904.png)\n\n## 分页器,可编辑字段,可跳转字段\n\n```Python\nlist_per_page = 20 # 一页显示多少条数据\nlist_editable = [\'status\'] # 可编辑的列\nlist_display_links = [\'title\', \'href\'] # 跳转到编辑页面\nempty_value_display = \'无\' # 字段为空显示的内容 默认是 -\n\n```\n\n![](http://python.fengfengzhidao.icu/img/20211018141531.png)\n\n## 添加记录\n\n修改默认显示字段\n\n![](http://python.fengfengzhidao.icu/img/20211018141914.png)\n\n默认添加记录的显示\n\n### 显示与隐藏字段\n\n```Python\nexclude = [\'company\', \'url\', \'title\', \'domain_num\', \'status\'] # 不显示的字段\n```\n\nexclude 中写上的字段不会显示\n\n```Python\nfields = [\'href\'] # 只显示的字段\n```\n\nfields 中写上的字段会显示\n\n![](http://python.fengfengzhidao.icu/img/20211018142351.png)\n\n有的字段,我们需要显示,但是提交的时候不能修改,例如数量\n\n```Python\nfields = [\'href\', \'domain_num\'] # 只显示的字段\nreadonly_fields = [\'domain_num\'] # 只读字段\n```\n\n![](http://python.fengfengzhidao.icu/img/20211018142610.png)\n\n第三种方案,将那些非必填项折叠起来\n\n```Python\nfieldsets = (\n (None, {\n \'fields\': (\'href\', \'title\')\n }),\n (\'其他字段\', {\n \'classes\': (\'collapse\',), # 必填\n \'fields\': (\'url\', \'company\', \'status\'),\n }),\n ) # 折叠列表, 和fields 使用冲突\n```\n\n![](http://python.fengfengzhidao.icu/img/20211018143149.png)\n\n## 保存前做点事\n\n很多时候,我们在添加或者修改记录的时候,需要提前做点事情\n\n例如,添加域名的时候,去src更新域名数\n\n操作,需要重写`save_model`方法\n\n```Python\ndef save_model(self, request, obj, form, change):\n \"\"\"\n self:当前表\n :param request: 请求对象\n :param obj: 字段对象\n :param form: 提交的数据 cleaned_data 在这里取值\n :param change: 是修改还是新增\n \"\"\"\n # 添加域名的时候,给父类的域名数量加 1\n if change:\n super().save_model(request, obj, form, change)\n else:\n obj.src_url.domain_num += 1 # 给父类的 domain_num加 1\n obj.src_url.save() # 父类对象调用 save方法进行保存\n super().save_model(request, obj, form, change) # 调用super方法,该干嘛干嘛\n```','2022-03-10 23:17:14.466099','2022-03-10 23:17:14.466099',1,1,4,0,0,0,2,'枫枫','枫枫知道个人博客',20,'',NULL,3972),(37,'网站关于','枫枫知道5.0系列\n再次在4.0的基础上不断创新\n进过四次迭代\n这次的博客摒弃了一些没用的功能,加强了用户常用功能\n枫枫知道\n全栈程序员一枚\n艺名:枫枫\n全称:枫枫知道\n分类划分','# FengfengBlog\n\n [简体中文](README.md)\n\n基于`python3.6.8`和`Django3.2.10`的博客。\n\n![image](https://img.shields.io/badge/blog-5.0.1-yellow.svg)\n[![image](https://img.shields.io/badge/fengfengblog-枫枫知道-orange.svg)](http://www.fengfengzhidao.com/)\n![image](https://img.shields.io/badge/license-Mysql5.7.26-blue.svg)\n\n## 主要功能:\n- 文章,页面,分类目录,标签的添加,删除,编辑等。文章及页面支持`Markdown`,支持代码高亮。\n- 支持文章全文搜索。\n- 主题切换功能,手机端适配。\n- 完整的评论功能,包括发表回复评论,支持`Markdown`。\n- 侧边栏功能,最新文章,最多阅读等。\n- 支持Oauth登陆,现已有QQ登录,gitee登录。\n- 集成了简单的图床功能。\n- 网站异常邮件提醒,若有未捕捉到的异常会自动发送提醒邮件。\n\n\n## 问题相关\n\n有任何问题欢迎提Issue,或者添加我的联系方式 2974771769(qq).我会尽快解答.推荐提交Issue方式. \n\n公测阶段遇到的任何项目相关的问题,都可以反馈于我。\n\n## 捐赠\n如果您觉得本项目对您有所帮助,欢迎您请我喝杯咖啡,您的支持是我最大的动力,您可以扫描下方二维码为我付款,谢谢。\n\n### 支付宝:\n<div>\n<img src=\"http://python.fengfengzhidao.com/pic/zhifubao_pay.jpg\" width=\"150\" height=\"150\" />\n</div>\n\n### 微信:\n<div>\n<img src=\"http://python.fengfengzhidao.com/pic/weixin_pay.jpg\" width=\"150\" height=\"150\" />\n</div>\n\n## 更新历史\n\n### 2022年5月11日\n1. 项目配置优化\n2. 网站关于优化\n3. 取消中间件中encoding的代码\n4. editormd的标题bug修复\n5. 文章悬浮目录首次加载异常bug修复\n\n### 2022年3月12日\n1. 完成项目录制工作\n2. 源码上传(未开源)','2022-03-03 22:23:39.089961','2022-03-10 22:50:05.164930',1,0,227,1,6,1,3,'枫枫','枫枫知道个人博客',19,'',NULL,1059),(38,'admin选择select选择图片','对应的类\nPython class MenuAdmin(admin.ModelAdmin): add_form_template = \'add_form.html\' # 添加的模板','对应的类\n\n```Python\nclass MenuAdmin(admin.ModelAdmin):\n add_form_template = \'add_form.html\' # 添加的模板\n change_form_template = \'add_form.html\' # 编辑的模板\n```\n\n\n\n\n\n```HTML\n{% extends \'admin/change_form.html\' %}\n{% block field_sets %}\n <style>\n #cover_res {\n width: 462px;\n height: 149px;\n border: 1px solid #f0eeee;\n position: absolute;\n border-radius: 5px;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);\n left: 570px;\n top: 59px;\n display: flex;\n flex-wrap: wrap;\n }\n\n #cover_res img {\n height: 60px;\n border-radius: 4px;\n margin-right: 10px;\n margin-bottom: 10px;\n }\n\n </style>\n <div id=\"cover_res\">\n <img :src=\"item\" v-for=\"(item,index) in cover_list\" :key=\"index\" alt=\"\">\n </div>\n {% for fieldset in adminform %}\n {% include \"admin/includes/fieldset.html\" %}\n {% endfor %}\n\n <script>\n let cover_vue = new Vue({\n el: \'#cover_res\',\n data: {\n cover_list: [],\n }\n })\n\n $(\'#menu_form\').css({\'position\': \'relative\'})\n // 计算预览框距离右边的距离\n let w_w = $(\'.related-widget-wrapper\').innerWidth()\n let label = $(\'[for=\"id_cover\"]\').innerWidth()\n\n // 计算这个预览框距离form的位置\n let t = $(\'[for=\"id_cover\"]\').offset().top\n let f = $(\'#menu_form\').offset().top\n \n $(\'#cover_res\').css({\n left: w_w + label + 15,\n top: t - f,\n })\n\n let cover = document.querySelector(\'#id_cover\')\n cover.onchange = (n) => {\n let option = $(\'#id_cover option:selected\')\n let lis = []\n for (const o of option) {\n lis.push(o.innerHTML)\n }\n cover_vue.cover_list = lis\n }\n </script>\n{% endblock %}\n```\n\n\n\n预览\n\n![](https://secure2.wostatic.cn/static/dXQAh6e2J7yHau61n8Goog/image.png)\n\n\n\n\n\n\n\n悬浮显示预览\n\n\n\n![](https://secure2.wostatic.cn/static/xv2hJhpJY5onFCHgYDmCsJ/image.png)\n\n\n\n```HTML\n{% extends \'admin/change_form.html\' %}\n{% block field_sets %}\n <style>\n #cover_res {\n width: 462px;\n height: 149px;\n border: 1px solid #f0eeee;\n position: absolute;\n border-radius: 5px;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);\n left: 570px;\n top: 59px;\n display: flex;\n flex-wrap: wrap;\n }\n\n #cover_res img {\n height: 60px;\n border-radius: 4px;\n margin-right: 10px;\n margin-bottom: 10px;\n }\n\n #cursor_hover {\n position: fixed;\n transition: all 0.3s;\n width: 150px;\n height: 100px;\n visibility: hidden;\n z-index: 1;\n }\n\n #cursor_hover img {\n width: 150px;\n height: 100px;\n object-fit: cover;\n border-radius: 5px;\n }\n\n </style>\n <div id=\"rrrwwww\">\n <div id=\"cursor_hover\">\n <img :src=\"img\" alt=\"\">\n </div>\n <div id=\"cover_res\">\n <img :src=\"item\" v-for=\"(item,index) in cover_list\" :key=\"index\" alt=\"\">\n </div>\n </div>\n\n {% for fieldset in adminform %}\n {% include \"admin/includes/fieldset.html\" %}\n {% endfor %}\n\n <script>\n let cover_vue = new Vue({\n el: \'#rrrwwww\',\n data: {\n cover_list: [],\n img: \'\',\n }\n })\n\n $(\'#menu_form\').css({\'position\': \'relative\'})\n // 计算预览框距离右边的距离\n let w_w = $(\'.related-widget-wrapper\').innerWidth()\n let label = $(\'[for=\"id_cover\"]\').innerWidth()\n\n // 计算这个预览框距离form的位置\n let t = $(\'[for=\"id_cover\"]\').offset().top\n let f = $(\'#menu_form\').offset().top\n $(\'#cover_res\').css({\n left: w_w + label + 15,\n top: t - f,\n })\n\n let cover = document.querySelector(\'#id_cover\')\n\n $(\'#id_cover option\').hover((e) => {\n cover_vue.img = e.target.innerHTML\n $(e.target).css({\n backgroundColor: \'#f0eeee\',\n })\n $(\'#cursor_hover\').css({\n left: e.pageX - 100,\n top: e.pageY - 120,\n visibility: \'visible\',\n })\n })\n $(\'#id_cover option\').mouseout((e) => {\n $(e.target).css({\n backgroundColor: \'\',\n })\n $(\'#cursor_hover\').css({\n left: e.pageX,\n top: e.pageY,\n visibility: \'hidden\',\n })\n })\n\n cover.onchange = (n) => {\n let option = $(\'#id_cover option:selected\')\n let lis = []\n for (const o of option) {\n lis.push(o.innerHTML)\n }\n cover_vue.cover_list = lis\n }\n </script>\n{% endblock %}\n```\n\n\n\n\n\n如何在详情页找到admin里面的配置项\n\n```HTML\n{{ adminform.model_admin }}\n```\n\n\n\n进一步封装\n\n```HTML\n{% extends \'admin/change_form.html\' %}\n{% load my_tag %}\n{% block field_sets %}\n\n\n {% for fieldset in adminform %}\n {% include \"admin/includes/fieldset.html\" %}\n {% endfor %}\n\n {% if adminform.model_admin.many2many %}\n <style>\n #cover_res {\n width: 462px;\n height: 149px;\n border: 1px solid #f0eeee;\n position: absolute;\n border-radius: 5px;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);\n left: 570px;\n top: 59px;\n display: flex;\n flex-wrap: wrap;\n }\n\n #cover_res img {\n height: 60px;\n border-radius: 4px;\n margin-right: 10px;\n margin-bottom: 10px;\n }\n\n #cursor_hover {\n position: fixed;\n transition: all 0.3s;\n width: 150px;\n height: 100px;\n visibility: hidden;\n z-index: 1;\n }\n\n #cursor_hover img {\n width: 150px;\n height: 100px;\n object-fit: cover;\n border-radius: 5px;\n }\n\n </style>\n <div id=\"{{ adminform.model_admin.many2many }}_root\">\n <div id=\"cursor_hover\">\n <img :src=\"img\" alt=\"\">\n </div>\n <div id=\"cover_res\">\n <img :src=\"item\" v-for=\"(item,index) in cover_list\" :key=\"index\" alt=\"\">\n </div>\n </div>\n <script>\n let cover_vue = new Vue({\n el: \'#{{ adminform.model_admin.many2many }}_root\',\n data: {\n cover_list: [],\n img: \'\',\n }\n })\n\n\n $(\'#menu_form\').css({\'position\': \'relative\'})\n // 计算预览框距离右边的距离\n let w_w = $(\'.related-widget-wrapper\').innerWidth()\n let label = $(\'[for=\"id_{{ adminform.model_admin.many2many }}\"]\').innerWidth()\n\n // 计算这个预览框距离form的位置\n let t = $(\'[for=\"id_{{ adminform.model_admin.many2many }}\"]\').offset().top\n let f = $(\'#menu_form\').offset().top\n $(\'#cover_res\').css({\n left: w_w + label + 15,\n top: t - f,\n })\n\n let cover = document.querySelector(\'#id_{{ adminform.model_admin.many2many }}\')\n\n $(\'#id_{{ adminform.model_admin.many2many }} option\').hover((e) => {\n cover_vue.img = e.target.innerHTML\n $(e.target).css({\n backgroundColor: \'#f0eeee\',\n })\n $(\'#cursor_hover\').css({\n left: e.pageX - 100,\n top: e.pageY - 120,\n visibility: \'visible\',\n })\n })\n $(\'#id_{{ adminform.model_admin.many2many }} option\').mouseout((e) => {\n $(e.target).css({\n backgroundColor: \'\',\n })\n $(\'#cursor_hover\').css({\n left: e.pageX,\n top: e.pageY,\n visibility: \'hidden\',\n })\n })\n\n cover.onchange = (n) => {\n let option = $(\'#id_{{ adminform.model_admin.many2many }} option:selected\')\n let lis = []\n for (const o of option) {\n lis.push(o.innerHTML)\n }\n cover_vue.cover_list = lis\n }\n </script>\n {% endif %}\n\n{% endblock %}\n```\n\n\n\n需要使用就在配置项中\n\n```Python\nclass MenuAdmin(admin.ModelAdmin):\n add_form_template = \'add_form.html\'\n change_form_template = \'add_form.html\'\n\n many2many = \'cover\' # 对应的字段名,目前只支持单个\n```','2022-03-04 20:52:26.701181','2022-03-10 22:50:05.160926',1,1,13,0,1,1,2,'枫枫','枫枫知道个人博客',17,'',NULL,8868),(39,'根据ip获取城市','获取ip\n```Python x_forwarded_for = request.META.get(\'HTTP_X_FORWARDED_FOR\') # 判断是否使用代理 if x_','获取ip\n\n```Python\nx_forwarded_for = request.META.get(\'HTTP_X_FORWARDED_FOR\') # 判断是否使用代理\nif x_forwarded_for:\n ip = x_forwarded_for.split(\',\')[0] # 使用代理获取真实的ip\nelse:\n ip = request.META.get(\'REMOTE_ADDR\') # 未使用代理获取IP\n\nprint(ip)\n```\n\n\n\n\n\n获取城市\n\n```Python\nimport requests\nimport re\n\nheaders = {\n \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) \"\n \"AppleWebKit/537.36 (KHTML, like Gecko) \"\n \"Chrome/98.0.4758.102 Safari/537.36\"\n}\n\n\ndef get_city(ip: str) -> dict:\n \"\"\"\n 合法 ip 返回国家,城市,和运营商\n 查不到运营商的就返回 国家,城市\n 内网 ip返回 内网\n :param ip:\n :return:\n \"\"\"\n # 构造返回的字典\n response = {\n \"country\": \'\',\n \"city\": \'\',\n }\n # 判断是否是内网 ip\n if ip.startswith(\'127\') or ip.startswith(\'192.\') or ip.startswith(\'10.\'):\n response[\'msg\'] = \'内网\'\n return response\n url = f\'https://ip.cn/ip/{ip}.html\'\n res = requests.get(url=url, headers=headers)\n result: str = re.findall(r\'<div id=\"tab0_address\">(.*?)</div>\', res.text)[0].strip()\n\n res_list = result.split(\' \')\n response[\'country\'] = res_list[0]\n city_or_operator = res_list[1]\n city = city_or_operator.split(\' \')\n response[\'city\'] = city[0] + \'-\' + city[1]\n if len(city) == 3:\n response[\'operator\'] = city[2]\n return response\n\n\nif __name__ == \'__main__\':\n print(get_city(\'127.0.0.1\'))\n print(get_city(\'192.168.44.33\'))\n print(get_city(\'117.136.24.38\'))\n print(get_city(\'218.76.35.2\'))\n print(get_city(\'110.53.253.137\'))\n print(get_city(\'36.99.136.139\'))\n print(get_city(\'106.13.185.190\'))\n print(get_city(\'42.194.130.81\'))\n\n```','2022-03-04 20:53:32.925817','2022-03-10 22:50:05.158924',1,1,65,0,11,1,2,'枫枫','枫枫知道个人博客',22,'',NULL,1621),(40,'el-scrollbar使用','给要实现滚动的地方包一个\nJavaScript <el-scrollbar style=\"height: 150px\"> 必须设置高度 <div id=\"avatar\"> 包裹区域','给要实现滚动的地方包一个\n\n```JavaScript\n<el-scrollbar style=\"height: 150px\"> 必须设置高度\n <div id=\"avatar\">\n 包裹区域\n </div>\n</el-scrollbar>\n```\n\n隐藏横向滚动条\n\n```JavaScript\n.el-scrollbar__wrap {\n overflow-x: hidden!important;\n}\n```\n\n\n\n全站使用\n\n```JavaScript\n<el-scrollbar ref=\"scrollbar\" style=\"height: 100vh\">\n <nav class=\"nav_bg\">\n </nav>\n {% block banner %}\n {% banner \'index\' %}\n {% endblock %}\n <main>\n </main>\n <footer>\n </footer>\n</el-scrollbar>\n```\n\n直接加上之后就会出现滚动效果,注意取消横向滚动条\n\n对于之前的动态导航就要在vue的mounted方法里面去实现\n\n```JavaScript\nmounted() {\n let bar = this.$refs.scrollbar.wrap\n slider = document.querySelector(\'.slider_bar\')\n let nav = document.querySelector(\'.nav_bg\')\n let top1 = 0;\n let path = location.pathname\n if (path.indexOf(\'article\') !== -1) {\n top1 = $(slider).offset().top - 80\n }\n bar.onscroll = () => {\n let top = bar.scrollTop\n if (top >= 200) {\n nav.classList.add(\'show\')\n } else {\n nav.classList.remove(\'show\')\n }\n\n if (slider) {\n if (top >= top1) {\n slider.classList.add(\'fixed\')\n } else {\n slider.classList.remove(\'fixed\')\n }\n }\n }\n},\n```\n\n文章详情页哪里\n\n```JavaScript\ninit_slider() {\n let flag = localStorage.getItem(\'isShowSlider\')\n setTimeout(() => {\n let box = document.querySelectorAll(\'.el-scrollbar__view\')[1]\n let height = box.offsetHeight\n if (height > 500) {\n height = 500\n } else if (height === 0) {\n height = 200\n }\n document.getElementById(\'el_scrollbar\').style.height = height + \'px\'\n }, 300)\n if (flag) {\n flag = eval(flag)\n this.isShowSlider = flag\n this.$nextTick(() => {\n this.sliderChange(flag)\n })\n }\n},\n```\n\n\n\n\n\n问题:\n\n- 刷新回到顶部\n- 方向键失效\n\n\n\n刷新回到顶部\n\njs监听窗口关闭,获取现在的滚动条位置,以及现在的url,写入到cookie\n\n打开页面,读取cookie和现在的url判断是否相等,相等则读取滚动条高度\n\n```HTML\n<script>\n new Vue({\n el: \'#app\',\n mounted() {\n this.init_scrollbar()\n\n },\n methods: {\n init_scrollbar() {\n let old_url = localStorage.getItem(\'current_url\')\n let new_url = location.href\n if (old_url === new_url) {\n // 刷新\n let top = localStorage.getItem(\'top\')\n localStorage.setItem(\'top\', \'0\')\n let el_bar = document.querySelector(\'.el-scrollbar__wrap\')\n $(el_bar).animate({scrollTop: top}, 0)\n }\n }\n }\n })\n \n let w = true; // 点击a标签的跳转就回到顶部\n $(\'a\').click(e => {\n w = false\n })\n window.onbeforeunload = e => {\n // 将滚动条的位置和当前url写入\n if (w) {\n let el_bar = document.querySelector(\'.el-scrollbar__wrap\')\n let url = location.href\n console.log(el_bar)\n localStorage.setItem(\'top\', el_bar.scrollTop)\n localStorage.setItem(\'current_url\', url)\n }\n };\n</script>\n```\n\n\n\n方向键\n\nwindow监听即可\n\n```JavaScript\nkeyDown() {\n // 监听键盘\n let el_bar = document.querySelector(\'.el-scrollbar__wrap\')\n document.onkeydown = (e) => {\n //事件对象兼容\n let e1 = e || event || window.event || arguments.callee.caller.arguments[0]\n let top = el_bar.scrollTop // 获取现在的位置\n if (e1.code === \'ArrowDown\') { // 下\n $(el_bar).animate({scrollTop: top + 20}, 0)\n } else if (e1.code === \'ArrowUp\') { // 上\n $(el_bar).animate({scrollTop: top - 20}, 0)\n }\n }\n},\n```','2022-03-04 21:02:49.911278','2022-03-10 22:50:05.156923',1,1,84,0,1,0,1,'枫枫','枫枫知道个人博客',18,'12345',NULL,3583);
/*!40000 ALTER TABLE `page_articles` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_articles_tag`
--
DROP TABLE IF EXISTS `page_articles_tag`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_articles_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`articles_id` int(11) NOT NULL,
`tags_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_articles_tag_articles_id_tags_id_f201463d_uniq` (`articles_id`,`tags_id`),
KEY `page_articles_tag_articles_id_c377df22` (`articles_id`),
KEY `page_articles_tag_tags_id_e0760570` (`tags_id`)
) ENGINE=MyISAM AUTO_INCREMENT=163 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_articles_tag`
--
LOCK TABLES `page_articles_tag` WRITE;
/*!40000 ALTER TABLE `page_articles_tag` DISABLE KEYS */;
INSERT INTO `page_articles_tag` VALUES (114,34,4),(129,2,4),(128,2,1),(97,4,1),(98,4,4),(108,7,4),(107,7,1),(156,43,4),(155,43,1),(152,39,1),(151,39,4),(150,39,19),(149,38,4),(148,38,3),(147,38,2),(153,40,2),(154,40,3),(162,37,18),(131,36,1),(144,1,4),(122,35,2),(123,35,4),(124,35,6),(125,35,16),(126,35,17),(115,34,6),(93,33,12),(132,32,2),(133,32,3),(130,31,1),(89,30,1),(88,29,1),(109,25,1),(85,28,1),(104,27,1),(105,27,4),(106,27,11),(102,26,2),(101,26,1),(103,26,4);
/*!40000 ALTER TABLE `page_articles_tag` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_avatars`
--
DROP TABLE IF EXISTS `page_avatars`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_avatars` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_avatars`
--
LOCK TABLES `page_avatars` WRITE;
/*!40000 ALTER TABLE `page_avatars` DISABLE KEYS */;
INSERT INTO `page_avatars` VALUES (1,'avatars/头像_0006_23.jpg'),(2,'avatars/头像_0005_24.jpg'),(3,'avatars/头像_0003_26.jpg'),(4,'avatars/头像_0002_27.jpg'),(12,'avatars/头像_0001_20.jpg'),(15,'avatars/头像_0007_22.jpg'),(8,'avatars/1.jpeg'),(16,'avatars/头像_0006_15.jpg'),(17,'avatars/头像_0004_25.jpg'),(18,'avatars/2.jpeg'),(19,'avatars/头像_0004_17.jpg');
/*!40000 ALTER TABLE `page_avatars` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_comment`
--
DROP TABLE IF EXISTS `page_comment`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_comment` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`digg_count` int(11) NOT NULL,
`content` longtext COLLATE utf8_unicode_ci NOT NULL,
`comment_count` int(11) NOT NULL,
`drawing` longtext COLLATE utf8_unicode_ci,
`create_time` datetime(6) NOT NULL,
`article_id` int(11) NOT NULL,
`parent_comment_id` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`nid`),
KEY `page_comment_article_id_2bf4f73b` (`article_id`),
KEY `page_comment_parent_comment_id_6a8024a5` (`parent_comment_id`),
KEY `page_comment_user_id_7f913f03` (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=126 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_comment`
--
LOCK TABLES `page_comment` WRITE;
/*!40000 ALTER TABLE `page_comment` DISABLE KEYS */;
INSERT INTO `page_comment` VALUES (125,0,'![emoji](https://face.t.sinajs.cn/t4/appstyle/expression/ext/normal/33/2018new_xixi_thumb.png)',0,NULL,'2022-05-11 21:54:34.022227',37,NULL,32);
/*!40000 ALTER TABLE `page_comment` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_cover`
--
DROP TABLE IF EXISTS `page_cover`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_cover` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`dominant_hue` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_dark` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_cover`
--
LOCK TABLES `page_cover` WRITE;
/*!40000 ALTER TABLE `page_cover` DISABLE KEYS */;
INSERT INTO `page_cover` VALUES (1,'article_img/21.jpg',NULL,NULL),(2,'article_img/22.jpg',NULL,NULL),(3,'article_img/24.jpg',NULL,NULL),(4,'article_img/29.jpg',NULL,NULL),(5,'article_img/40.jpg',NULL,NULL),(6,'article_img/38.jpg',NULL,NULL),(7,'article_img/31.jpg',NULL,NULL),(8,'article_img/27.jpg',NULL,NULL),(9,'article_img/33.jpg',NULL,NULL),(10,'article_img/28.jpg',NULL,NULL),(11,'article_img/鲜艳.png',NULL,NULL),(12,'article_img/飞机.png',NULL,NULL),(13,'article_img/小汽车.png',NULL,NULL),(14,'article_img/绿色.png',NULL,NULL),(16,'article_img/shouhuiyuhangyuan.png',NULL,NULL),(17,'article_img/republic-of-gamers-8-bit-3n.jpg',NULL,NULL),(18,'article_img/5-32.jpg',NULL,NULL),(19,'article_img/t010de4d8be79be281c.jpg',NULL,NULL),(20,'article_img/地球.png',NULL,NULL),(21,'article_img/宇宙.png',NULL,NULL),(22,'article_img/紫色.png',NULL,NULL);
/*!40000 ALTER TABLE `page_cover` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_feedback`
--
DROP TABLE IF EXISTS `page_feedback`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_feedback` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(254) COLLATE utf8_unicode_ci NOT NULL,
`content` longtext COLLATE utf8_unicode_ci NOT NULL,
`status` tinyint(1) NOT NULL,
`processing_content` longtext COLLATE utf8_unicode_ci,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_feedback`
--
LOCK TABLES `page_feedback` WRITE;
/*!40000 ALTER TABLE `page_feedback` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_feedback` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_history`
--
DROP TABLE IF EXISTS `page_history`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_history` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`content` longtext COLLATE utf8_unicode_ci NOT NULL,
`create_date` date DEFAULT NULL,
`drawing` longtext COLLATE utf8_unicode_ci,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_history`
--
LOCK TABLES `page_history` WRITE;
/*!40000 ALTER TABLE `page_history` DISABLE KEYS */;
INSERT INTO `page_history` VALUES (1,'新增七牛云图片上传','实现七牛云的图片上传\n图片预览','2022-02-28','http://python.fengfengzhidao.com/blog/1646052356.png'),(2,'滚动条样式美化','使用elementui美化滚动条\nonsroll加载问题处理','2022-02-25','http://python.fengfengzhidao.com/blog/1646052839.png\nhttp://python.fengfengzhidao.com/blog/1646052895.png'),(3,'处理django上传大小限制','处理上传大小限制\n优化上传逻辑','2022-02-28','http://python.fengfengzhidao.com/blog/1646053053.png\nhttp://python.fengfengzhidao.com/blog/1646053066.png'),(18,'优化网站导航页面','全新的网站导航\n前后端分离','2022-03-01','http://python.fengfengzhidao.com/blog/1646146225.png'),(19,'完成网站导航','网站导航标签的增删改查\n网站导航网站的增删改查\n标签滚动事件','2022-03-03','http://python.fengfengzhidao.com/blog/1646317064.png'),(20,'项目分类与表情','完成项目分类\n完成评论添加标签','2022-03-06','http://python.fengfengzhidao.com/blog/1646567812.png\nhttp://python.fengfengzhidao.com/blog/1646567861.png');
/*!40000 ALTER TABLE `page_history` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_menu`
--
DROP TABLE IF EXISTS `page_menu`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_menu` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`menu_title` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`menu_title_en` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`title` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`abstract` longtext COLLATE utf8_unicode_ci,
`abstract_time` int(11) NOT NULL,
`rotation` tinyint(1) NOT NULL,
`menu_rotation` tinyint(1) NOT NULL,
`menu_time` int(11) NOT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_menu`
--
LOCK TABLES `page_menu` WRITE;
/*!40000 ALTER TABLE `page_menu` DISABLE KEYS */;
INSERT INTO `page_menu` VALUES (1,'首页','index','枫枫知道','关于枫枫知道 更快更强!\r\n全新五代,更快更强!',8,1,1,4),(2,'新闻','news','今日热搜','关注国家大事',8,1,1,8),(3,'心情','moods','发布你的心情','不需要登录就可以发送哦~;赶紧来发一篇吧~',8,0,0,8),(4,'回忆录','history','建站回忆录','枫枫知道个人博客建站回忆',8,0,0,8),(5,'关于','about','网站关于','关于枫枫知道的个人博客',8,0,1,8),(6,'网站导航','sites','网站导航','最新一代的网址导航',8,1,1,8),(7,'项目相关','project','个人博客项目','需要学习个人博客的可以联系我',8,1,1,8);
/*!40000 ALTER TABLE `page_menu` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_menu_menu_url`
--
DROP TABLE IF EXISTS `page_menu_menu_url`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_menu_menu_url` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`menu_id` int(11) NOT NULL,
`menuimg_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_menu_menu_url_menu_id_menuimg_id_9b80b024_uniq` (`menu_id`,`menuimg_id`),
KEY `page_menu_menu_url_menu_id_fe74c303` (`menu_id`),
KEY `page_menu_menu_url_menuimg_id_c89e39bd` (`menuimg_id`)
) ENGINE=MyISAM AUTO_INCREMENT=30 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_menu_menu_url`
--
LOCK TABLES `page_menu_menu_url` WRITE;
/*!40000 ALTER TABLE `page_menu_menu_url` DISABLE KEYS */;
INSERT INTO `page_menu_menu_url` VALUES (1,1,1),(2,1,2),(3,1,3),(4,1,4),(5,1,5),(6,2,3),(7,2,5),(8,3,2),(9,3,4),(18,4,7),(17,4,6),(16,4,8),(22,5,10),(21,5,9),(23,5,11),(24,6,2),(25,6,3),(26,6,5),(27,6,7),(28,7,8),(29,7,9);
/*!40000 ALTER TABLE `page_menu_menu_url` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_menuimg`
--
DROP TABLE IF EXISTS `page_menuimg`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_menuimg` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`dominant_hue` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_dark` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_menuimg`
--
LOCK TABLES `page_menuimg` WRITE;
/*!40000 ALTER TABLE `page_menuimg` DISABLE KEYS */;
INSERT INTO `page_menuimg` VALUES (1,'site_bg/宇宙.png',NULL,NULL),(2,'site_bg/t010de4d8be79be281c.jpg',NULL,NULL),(3,'site_bg/飞机.png',NULL,NULL),(4,'site_bg/29.jpg',NULL,NULL),(5,'site_bg/31.jpg',NULL,NULL),(6,'site_bg/34.jpg',NULL,NULL),(7,'site_bg/28.jpg',NULL,NULL),(8,'site_bg/绿色.png',NULL,NULL),(9,'site_bg/img_2.png',NULL,NULL),(10,'site_bg/img_3.png',NULL,NULL),(11,'site_bg/img_10.jpg',NULL,NULL);
/*!40000 ALTER TABLE `page_menuimg` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_moodcomment`
--
DROP TABLE IF EXISTS `page_moodcomment`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_moodcomment` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`content` longtext COLLATE utf8_unicode_ci NOT NULL,
`digg_count` int(11) NOT NULL,
`create_date` datetime(6) NOT NULL,
`avatar_id` int(11) DEFAULT NULL,
`mood_id` int(11) DEFAULT NULL,
`addr` longtext COLLATE utf8_unicode_ci,
`ip` char(39) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`nid`),
KEY `page_moodcomment_avatar_id_20ee4ce3` (`avatar_id`),
KEY `page_moodcomment_mood_id_f0b5317e` (`mood_id`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_moodcomment`
--
LOCK TABLES `page_moodcomment` WRITE;
/*!40000 ALTER TABLE `page_moodcomment` DISABLE KEYS */;
INSERT INTO `page_moodcomment` VALUES (14,'1','2',0,'2022-03-04 19:49:59.445529',2,NULL,'{\"city\": \"内网\", \"prov\": \"中国\"}','127.0.0.1'),(13,'45fdg','sdh',0,'2022-03-03 23:48:31.958638',4,9,'{\"city\": \"内网\", \"prov\": \"中国\"}','127.0.0.1'),(12,'还好还好','硅谷',5,'2022-02-23 14:57:24.315291',2,9,'{\"city\": \"内网\", \"prov\": \"中国\"}','127.0.0.1');
/*!40000 ALTER TABLE `page_moodcomment` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_moods`
--
DROP TABLE IF EXISTS `page_moods`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_moods` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
`create_date` datetime(6) NOT NULL,
`content` longtext COLLATE utf8_unicode_ci NOT NULL,
`drawing` longtext COLLATE utf8_unicode_ci,
`comment_count` int(11) NOT NULL,
`digg_count` int(11) NOT NULL,
`avatar_id` int(11) DEFAULT NULL,
`addr` longtext COLLATE utf8_unicode_ci,
`ip` char(39) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`nid`),
KEY `page_moods_avatar_id_f891277b` (`avatar_id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_moods`
--
LOCK TABLES `page_moods` WRITE;
/*!40000 ALTER TABLE `page_moods` DISABLE KEYS */;
INSERT INTO `page_moods` VALUES (1,'枫枫','2022-02-23 00:19:46.507023','博客第一条心情',NULL,0,0,1,'{\"ct\": \"中国\", \"city\": \"南京市\", \"prov\": \"江苏省\", \"yunyin\": \"百度云\"}','106.13.185.190'),(3,'张三','2022-02-23 00:19:46.673174','测试发布图片','https://img1.baidu.com/it/u=793269991,2224346596&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',0,1,4,'{\"ct\": \"中国\", \"area\": \"岳麓区\", \"city\": \"长沙市\", \"prov\": \"湖南省\", \"yunyin\": \"移动\"}','120.228.2.238'),(4,'测试用户','2022-02-23 00:19:46.756250','哈哈哈','https://img2.baidu.com/it/u=1638649045,2444334177&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500;\nhttps://img2.baidu.com/it/u=3804069081,3968854353&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',0,1,2,'{\"ct\": \"中国\", \"area\": \"岳麓区\", \"city\": \"长沙市\", \"prov\": \"湖南省\", \"yunyin\": \"移动\"}','120.228.2.238'),(5,'李四','2022-02-23 00:31:27.056994','今天天气不错啊','https://i2.hdslb.com/bfs/archive/f5f3be47b3ddc4ad131a1920ccb4c858ec8401f9.jpg@672w_378h_1c.webp',0,0,3,'{\"ct\": \"中国\", \"area\": \"岳麓区\", \"city\": \"长沙市\", \"prov\": \"湖南省\", \"yunyin\": \"移动\"}','192.168.31.136'),(9,'猪仔','2022-02-23 14:56:19.828688','哈哈哈哈哈哈啊哈哈哈','http://tva1.sinaimg.cn/bmiddle/006qir4oly1gz08s3pwzuj30j60j6jsi.jpg\nhttp://tva1.sinaimg.cn/bmiddle/006qir4oly1gz08s3vqjvj30go0gqaaj.jpg',2,16,4,'{\"city\": \"内网\", \"prov\": \"中国\"}','127.0.0.1');
/*!40000 ALTER TABLE `page_moods` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_navs`
--
DROP TABLE IF EXISTS `page_navs`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_navs` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`icon_href` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
`title` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`abstract` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
`create_date` datetime(6) NOT NULL,
`href` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`status` int(11) NOT NULL,
`collects_count` int(11) NOT NULL,
`digg_count` int(11) NOT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=26 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_navs`
--
LOCK TABLES `page_navs` WRITE;
/*!40000 ALTER TABLE `page_navs` DISABLE KEYS */;
INSERT INTO `page_navs` VALUES (1,'http://python.fengfengzhidao.com/blog/1646404652.png','枫枫的个人博客','分享知识,主攻前端和后端,一起学习交流','2022-03-02 21:40:43.642038','http://www.fengfengzhidao.com',1,1,3455),(2,'https://element.faas.ele.me/favicon.ico','element UI','一款基于vue的UI框架','2022-03-02 21:40:51.523611','https://element.faas.ele.me/',1,1,50),(6,'https://www.bilibili.com/favicon.ico?v=1','哔哩哔哩 (゜-゜)つロ 干杯~','bilibili是国内知名的视频弹幕网站,这里有及时的动漫新番,活跃的ACG氛围,有创意的Up主。大家可以在这里找到许多欢乐。','2022-03-02 21:40:37.049010','https://www.bilibili.com/',1,2,460),(5,'https://636f-codenav-8grj8px727565176-1256524210.tcb.qcloud.la/img/logo.png','编程导航','编程导航,发现优质编程学习资源','2022-03-02 00:24:19.733926','https://www.code-nav.cn/',1,1,4),(7,'https://cuiqingcai.com/images/avatar.png','崔庆才的个人站点','崔庆才的个人站点,记录生活的瞬间,分享学习的心得。','2022-03-02 20:51:44.242017','https://cuiqingcai.com/',1,0,0),(11,'https://undraw.co/favicon.ico','unDraw','The design project with open-source illustrations for any idea you can imagine and create. Create beautiful websites','2022-03-03 21:06:16.236573','https://undraw.co/',1,0,0),(10,'https://cn.vuejs.org/images/logo.svg','Vue官方网站','不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。','2022-03-02 21:40:15.726505','https://cn.vuejs.org/v2/guide/syntax.html',1,1,9),(12,'https://fastly.jsdelivr.net/npm/@bootcss/[email protected]/favicon.ico','Bootstrap','Bootstrap 是最受欢迎的 HTML、CSS 和 JavaScript 框架,用于开发响应式布局、移动设备优先的 WEB 项目。','2022-03-03 21:07:31.270824','https://v3.bootcss.com/',1,0,0),(13,'http://www.jq22.com/favicon.ico','jQuery插件库','本站致力于收集jQuery插件和提供各种jQuery特效的详细使用方法,在线预览,jQuery插件下载及教程','2022-03-03 21:08:46.551452','https://www.jq22.com/',1,0,0),(14,'https://go.itab.link/favicon.svg','iTab新标签页','自定义您新标签页上的网站和壁纸以及搜索引擎,创建和编辑属于您自己的浏览器标签页,精美日历、炫酷天气、每日头条、海量壁纸、常用网址随心订制','2022-03-03 21:10:11.705045','https://go.itab.link/',1,0,0),(15,'https://www.bootcdn.cn/assets/ico/favicon.ico?1645893451584','BootCDN','Bootstrap 中文网开源项目免费 CDN 加速服务 - 我们致力于为 Bootstrap、jQuery、Angular、Vue.js 一样优秀的开源项目提供稳定、快速、免费的 CDN 加速服务','2022-03-03 21:11:35.826402','https://www.bootcdn.cn/',1,0,0),(16,'https://www.qingqingblog.com/skin/html/images/star.png','杨青青个人博客','杨青青,80后女程序员,个人博客网站提供免费的个人博客搭建教程,个人博客网站模板下载,以及分享一些前端个人博客设计等知识。','2022-03-03 21:13:00.573504','https://www.qingqingblog.com/',1,0,0),(17,'https://image.3001.net/images/20200922/16007336487809.jpg','归档 | 国光','归档, 国光,Termux,Web安全,黑苹果','2022-03-03 21:15:23.790936','https://www.sqlsec.com/avs/',1,0,0),(18,'https://connect.qq.com/favicon.ico','QQ开放平台','QQ互联官网首页|网站接入|第三方登录','2022-03-03 21:20:49.429736','https://connect.qq.com/',1,0,0),(19,'https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico','微信开放平台','微信开放平台|微信登录|第三方接入','2022-03-03 21:22:10.860905','https://open.weixin.qq.com/',1,0,0),(20,'https://www.wenyuanblog.com/favicon.png','文渊博客','文渊博客 - 程序员的个人博客 | 一个90后程序员的技术人生','2022-03-03 21:24:10.810922','https://www.wenyuanblog.com/',1,0,2),(21,'https://www.bt.cn/Public/img/btlogo.png','宝塔面板','宝塔Linux面板是提升运维效率的服务器管理软件,支持一键LAMP/LNMP/集群/监控/网站/FTP/数据库/JAVA等100多项服务器管理功能。','2022-03-03 21:25:36.815180','https://www.bt.cn/',1,0,0),(24,'https://assets.retiehe.com/ap-icon-192-2.png','AirPortal','AirPortal(空投快传)是一个可以跨设备传输文件的网站。只要您的设备联网,您就可以通过它在任意系统、任意设备间传输文件。无需登录或注册,只需打开空投快传、直接上传文件、记住所给的取件码或直接扫描二维码即可在另一台设备上下载文件。','2022-03-06 19:39:57.924460','https://airportal.cn/',1,0,0),(22,'http://python.fengfengzhidao.com/blog/1646404652.png','枫枫知道个人博客','喜欢敲代码的个人博客博主','2022-03-04 22:38:25.397868','http://www.fengfengzhidao.com',1,0,0),(23,'https://z3.ax1x.com/2021/11/11/IwdU9H.jpg','迪迪亚与前端','BB观察站的科普收集','2022-03-04 22:40:25.415838','https://bb5bb.cn/',0,0,0),(25,'https://cdn.jsdelivr.net/gh/MobiusBeta/assets/images/Lime_Logo.png','青柠起始页','青柠起始页由毛若昕和杨尚臻开发,是一个简洁、美观、实用的浏览器起始页。青柠起始页以最简洁的界面容纳了多引擎搜索、自定义网站捷径、便笺等实用功能;您可依据喜好对青柠起始页进行高度自定义,让您的网上冲浪体验更加舒心。','2022-03-06 19:50:55.173938','https://limestart.cn/',1,0,0);
/*!40000 ALTER TABLE `page_navs` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_navs_tag`
--
DROP TABLE IF EXISTS `page_navs_tag`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_navs_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`navs_id` int(11) NOT NULL,
`navtags_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_navs_tag_navs_id_navtags_id_39e10941_uniq` (`navs_id`,`navtags_id`),
KEY `page_navs_tag_navs_id_64df90b2` (`navs_id`),
KEY `page_navs_tag_navtags_id_e997acfd` (`navtags_id`)
) ENGINE=MyISAM AUTO_INCREMENT=68 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_navs_tag`
--
LOCK TABLES `page_navs_tag` WRITE;
/*!40000 ALTER TABLE `page_navs_tag` DISABLE KEYS */;
INSERT INTO `page_navs_tag` VALUES (61,1,2),(60,1,1),(62,1,6),(23,2,4),(5,5,1),(6,5,2),(7,5,3),(8,5,4),(9,6,1),(10,6,2),(11,7,2),(22,2,3),(21,2,2),(20,2,1),(42,10,4),(63,1,9),(41,10,1),(40,10,8),(43,11,12),(44,12,13),(45,13,14),(55,14,16),(47,15,17),(48,16,15),(49,17,15),(50,18,20),(51,19,20),(52,20,15),(53,21,24),(54,21,23),(56,14,10),(57,14,11),(58,22,15),(59,23,15),(64,24,16),(65,24,1),(66,25,16),(67,25,1);
/*!40000 ALTER TABLE `page_navs_tag` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_navtags`
--
DROP TABLE IF EXISTS `page_navtags`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_navtags` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=25 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_navtags`
--
LOCK TABLES `page_navtags` WRITE;
/*!40000 ALTER TABLE `page_navtags` DISABLE KEYS */;
INSERT INTO `page_navtags` VALUES (1,'推荐'),(2,'教程'),(3,'Python'),(4,'Vue'),(6,'最新'),(7,'框架'),(8,'源码'),(9,'Django'),(10,'摸鱼'),(11,'吃喝玩乐'),(12,'设计'),(13,'前端'),(14,'插件'),(15,'博客'),(16,'好物分享'),(17,'CDN分享'),(18,'文档'),(19,'JavaScript'),(20,'开放平台'),(21,'go'),(22,'生活'),(23,'工具'),(24,'运维');
/*!40000 ALTER TABLE `page_navtags` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_project`
--
DROP TABLE IF EXISTS `page_project`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_project` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_project`
--
LOCK TABLES `page_project` WRITE;
/*!40000 ALTER TABLE `page_project` DISABLE KEYS */;
INSERT INTO `page_project` VALUES (1,'python基础'),(2,'django基础'),(3,'博客开发'),(4,'项目部署');
/*!40000 ALTER TABLE `page_project` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_project_article`
--
DROP TABLE IF EXISTS `page_project_article`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_project_article` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`project_id` int(11) NOT NULL,
`articles_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_project_article_project_id_articles_id_b7f48fe3_uniq` (`project_id`,`articles_id`),
KEY `page_project_article_project_id_07730480` (`project_id`),
KEY `page_project_article_articles_id_baf31051` (`articles_id`)
) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_project_article`
--
LOCK TABLES `page_project_article` WRITE;
/*!40000 ALTER TABLE `page_project_article` DISABLE KEYS */;
INSERT INTO `page_project_article` VALUES (1,1,36),(2,1,25),(3,1,28),(4,1,29),(5,1,30),(6,1,31),(8,3,26),(9,3,27),(10,4,34),(13,2,1);
/*!40000 ALTER TABLE `page_project_article` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_tags`
--
DROP TABLE IF EXISTS `page_tags`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_tags` (
`nid` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`nid`)
) ENGINE=MyISAM AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_tags`
--
LOCK TABLES `page_tags` WRITE;
/*!40000 ALTER TABLE `page_tags` DISABLE KEYS */;
INSERT INTO `page_tags` VALUES (1,'python'),(2,'Vue'),(3,'javascript'),(4,'Django'),(5,'Node'),(6,'项目部署'),(7,'css'),(8,'DRF'),(9,'多对多'),(10,'一对多'),(11,'分页器'),(12,'react'),(13,'ORM'),(14,'Mysql'),(15,'redis'),(16,'nginx'),(17,'linux'),(18,'关于'),(19,'爬虫');
/*!40000 ALTER TABLE `page_tags` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_userinfo`
--
DROP TABLE IF EXISTS `page_userinfo`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_userinfo` (
`password` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`last_login` datetime(6) DEFAULT NULL,
`is_superuser` tinyint(1) NOT NULL,
`username` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`first_name` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(254) COLLATE utf8_unicode_ci NOT NULL,
`is_staff` tinyint(1) NOT NULL,
`is_active` tinyint(1) NOT NULL,
`date_joined` datetime(6) NOT NULL,
`nid` int(11) NOT NULL AUTO_INCREMENT,
`nick_name` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
`sign_status` int(11) NOT NULL,
`tel` varchar(12) COLLATE utf8_unicode_ci DEFAULT NULL,
`integral` int(11) NOT NULL,
`avatar_id` int(11) DEFAULT NULL,
`account_status` int(11) NOT NULL,
`avatar_url` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
`token` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`addr` longtext COLLATE utf8_unicode_ci,
`ip` char(39) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`nid`),
UNIQUE KEY `username` (`username`),
KEY `page_userinfo_avatar_id_4d8395aa` (`avatar_id`)
) ENGINE=MyISAM AUTO_INCREMENT=33 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_userinfo`
--
LOCK TABLES `page_userinfo` WRITE;
/*!40000 ALTER TABLE `page_userinfo` DISABLE KEYS */;
INSERT INTO `page_userinfo` VALUES ('pbkdf2_sha256$260000$EeKDBCXjv1lud2dlQFK5DF$nbfPAPYCwQivlzHkru5VzZoF3TLA1VtJOY/qnS6VIwc=','2022-05-11 21:41:33.505345',1,'admin','','','',1,1,'2022-03-12 00:49:00.000000',32,'admin',0,NULL,20,3,0,NULL,NULL,NULL,'120.228.2.238');
/*!40000 ALTER TABLE `page_userinfo` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_userinfo_collects`
--
DROP TABLE IF EXISTS `page_userinfo_collects`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_userinfo_collects` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userinfo_id` int(11) NOT NULL,
`articles_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_userinfo_collects_userinfo_id_articles_id_73774dcd_uniq` (`userinfo_id`,`articles_id`),
KEY `page_userinfo_collects_userinfo_id_eab70bce` (`userinfo_id`),
KEY `page_userinfo_collects_articles_id_c3773049` (`articles_id`)
) ENGINE=MyISAM AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_userinfo_collects`
--
LOCK TABLES `page_userinfo_collects` WRITE;
/*!40000 ALTER TABLE `page_userinfo_collects` DISABLE KEYS */;
INSERT INTO `page_userinfo_collects` VALUES (35,32,25);
/*!40000 ALTER TABLE `page_userinfo_collects` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_userinfo_groups`
--
DROP TABLE IF EXISTS `page_userinfo_groups`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_userinfo_groups` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userinfo_id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_userinfo_groups_userinfo_id_group_id_48ba2aa6_uniq` (`userinfo_id`,`group_id`),
KEY `page_userinfo_groups_userinfo_id_04be482a` (`userinfo_id`),
KEY `page_userinfo_groups_group_id_30b9b2c4` (`group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_userinfo_groups`
--
LOCK TABLES `page_userinfo_groups` WRITE;
/*!40000 ALTER TABLE `page_userinfo_groups` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_userinfo_groups` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_userinfo_navs`
--
DROP TABLE IF EXISTS `page_userinfo_navs`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_userinfo_navs` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userinfo_id` int(11) NOT NULL,
`navs_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_userinfo_navs_userinfo_id_navs_id_197774e8_uniq` (`userinfo_id`,`navs_id`),
KEY `page_userinfo_navs_userinfo_id_40eb4ed6` (`userinfo_id`),
KEY `page_userinfo_navs_navs_id_1ea72c9c` (`navs_id`)
) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_userinfo_navs`
--
LOCK TABLES `page_userinfo_navs` WRITE;
/*!40000 ALTER TABLE `page_userinfo_navs` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_userinfo_navs` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `page_userinfo_user_permissions`
--
DROP TABLE IF EXISTS `page_userinfo_user_permissions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `page_userinfo_user_permissions` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userinfo_id` int(11) NOT NULL,
`permission_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `page_userinfo_user_perm_userinfo_id_permission_i_8bd06903_uniq` (`userinfo_id`,`permission_id`),
KEY `page_userinfo_user_permissions_userinfo_id_3a67a872` (`userinfo_id`),
KEY `page_userinfo_user_permissions_permission_id_826033c9` (`permission_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `page_userinfo_user_permissions`
--
LOCK TABLES `page_userinfo_user_permissions` WRITE;
/*!40000 ALTER TABLE `page_userinfo_user_permissions` DISABLE KEYS */;
/*!40000 ALTER TABLE `page_userinfo_user_permissions` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `auth_group`
--
DROP TABLE IF EXISTS `auth_group`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `auth_group` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `auth_group`
--
LOCK TABLES `auth_group` WRITE;
/*!40000 ALTER TABLE `auth_group` DISABLE KEYS */;
/*!40000 ALTER TABLE `auth_group` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `auth_group_permissions`
--
DROP TABLE IF EXISTS `auth_group_permissions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `auth_group_permissions` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`group_id` int(11) NOT NULL,
`permission_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `auth_group_permissions_group_id_permission_id_0cd325b0_uniq` (`group_id`,`permission_id`),
KEY `auth_group_permissions_group_id_b120cbf9` (`group_id`),
KEY `auth_group_permissions_permission_id_84c5c92e` (`permission_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `auth_group_permissions`
--
LOCK TABLES `auth_group_permissions` WRITE;
/*!40000 ALTER TABLE `auth_group_permissions` DISABLE KEYS */;
/*!40000 ALTER TABLE `auth_group_permissions` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `auth_permission`
--
DROP TABLE IF EXISTS `auth_permission`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `auth_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`content_type_id` int(11) NOT NULL,
`codename` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `auth_permission_content_type_id_codename_01ab375a_uniq` (`content_type_id`,`codename`),
KEY `auth_permission_content_type_id_2f476e4b` (`content_type_id`)
) ENGINE=MyISAM AUTO_INCREMENT=105 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `auth_permission`
--
LOCK TABLES `auth_permission` WRITE;
/*!40000 ALTER TABLE `auth_permission` DISABLE KEYS */;
INSERT INTO `auth_permission` VALUES (1,'Can add log entry',1,'add_logentry'),(2,'Can change log entry',1,'change_logentry'),(3,'Can delete log entry',1,'delete_logentry'),(4,'Can view log entry',1,'view_logentry'),(5,'Can add permission',2,'add_permission'),(6,'Can change permission',2,'change_permission'),(7,'Can delete permission',2,'delete_permission'),(8,'Can view permission',2,'view_permission'),(9,'Can add group',3,'add_group'),(10,'Can change group',3,'change_group'),(11,'Can delete group',3,'delete_group'),(12,'Can view group',3,'view_group'),(13,'Can add content type',4,'add_contenttype'),(14,'Can change content type',4,'change_contenttype'),(15,'Can delete content type',4,'delete_contenttype'),(16,'Can view content type',4,'view_contenttype'),(17,'Can add session',5,'add_session'),(18,'Can change session',5,'change_session'),(19,'Can delete session',5,'delete_session'),(20,'Can view session',5,'view_session'),(21,'Can add user info',6,'add_userinfo'),(22,'Can change user info',6,'change_userinfo'),(23,'Can delete user info',6,'delete_userinfo'),(24,'Can view user info',6,'view_userinfo'),(25,'Can add advert',7,'add_advert'),(26,'Can change advert',7,'change_advert'),(27,'Can delete advert',7,'delete_advert'),(28,'Can view advert',7,'view_advert'),(29,'Can add articles',8,'add_articles'),(30,'Can change articles',8,'change_articles'),(31,'Can delete articles',8,'delete_articles'),(32,'Can view articles',8,'view_articles'),(33,'Can add avatars',9,'add_avatars'),(34,'Can change avatars',9,'change_avatars'),(35,'Can delete avatars',9,'delete_avatars'),(36,'Can view avatars',9,'view_avatars'),(37,'Can add cover',10,'add_cover'),(38,'Can change cover',10,'change_cover'),(39,'Can delete cover',10,'delete_cover'),(40,'Can view cover',10,'view_cover'),(41,'Can add feedback',11,'add_feedback'),(42,'Can change feedback',11,'change_feedback'),(43,'Can delete feedback',11,'delete_feedback'),(44,'Can view feedback',11,'view_feedback'),(45,'Can add history',12,'add_history'),(46,'Can change history',12,'change_history'),(47,'Can delete history',12,'delete_history'),(48,'Can view history',12,'view_history'),(49,'Can add menu img',13,'add_menuimg'),(50,'Can change menu img',13,'change_menuimg'),(51,'Can delete menu img',13,'delete_menuimg'),(52,'Can view menu img',13,'view_menuimg'),(53,'Can add my info',14,'add_myinfo'),(54,'Can change my info',14,'change_myinfo'),(55,'Can delete my info',14,'delete_myinfo'),(56,'Can view my info',14,'view_myinfo'),(57,'Can add nav category',15,'add_navcategory'),(58,'Can change nav category',15,'change_navcategory'),(59,'Can delete nav category',15,'delete_navcategory'),(60,'Can view nav category',15,'view_navcategory'),(61,'Can add new',16,'add_new'),(62,'Can change new',16,'change_new'),(63,'Can delete new',16,'delete_new'),(64,'Can view new',16,'view_new'),(65,'Can add site',17,'add_site'),(66,'Can change site',17,'change_site'),(67,'Can delete site',17,'delete_site'),(68,'Can view site',17,'view_site'),(69,'Can add tags',18,'add_tags'),(70,'Can change tags',18,'change_tags'),(71,'Can delete tags',18,'delete_tags'),(72,'Can view tags',18,'view_tags'),(73,'Can add navs',19,'add_navs'),(74,'Can change navs',19,'change_navs'),(75,'Can delete navs',19,'delete_navs'),(76,'Can view navs',19,'view_navs'),(77,'Can add moods',20,'add_moods'),(78,'Can change moods',20,'change_moods'),(79,'Can delete moods',20,'delete_moods'),(80,'Can view moods',20,'view_moods'),(81,'Can add mood comment',21,'add_moodcomment'),(82,'Can change mood comment',21,'change_moodcomment'),(83,'Can delete mood comment',21,'delete_moodcomment'),(84,'Can view mood comment',21,'view_moodcomment'),(85,'Can add menu',22,'add_menu'),(86,'Can change menu',22,'change_menu'),(87,'Can delete menu',22,'delete_menu'),(88,'Can view menu',22,'view_menu'),(89,'Can add comment',23,'add_comment'),(90,'Can change comment',23,'change_comment'),(91,'Can delete comment',23,'delete_comment'),(92,'Can view comment',23,'view_comment'),(93,'Can add nav tags',24,'add_navtags'),(94,'Can change nav tags',24,'change_navtags'),(95,'Can delete nav tags',24,'delete_navtags'),(96,'Can view nav tags',24,'view_navtags'),(97,'Can add project',25,'add_project'),(98,'Can change project',25,'change_project'),(99,'Can delete project',25,'delete_project'),(100,'Can view project',25,'view_project'),(101,'Can add email',26,'add_email'),(102,'Can change email',26,'change_email'),(103,'Can delete email',26,'delete_email'),(104,'Can view email',26,'view_email');
/*!40000 ALTER TABLE `auth_permission` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `django_admin_log`
--
DROP TABLE IF EXISTS `django_admin_log`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `django_admin_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`action_time` datetime(6) NOT NULL,
`object_id` longtext COLLATE utf8_unicode_ci,
`object_repr` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`action_flag` smallint(5) unsigned NOT NULL,
`change_message` longtext COLLATE utf8_unicode_ci NOT NULL,
`content_type_id` int(11) DEFAULT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `django_admin_log_content_type_id_c4bce8eb` (`content_type_id`),
KEY `django_admin_log_user_id_c564eba6` (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=194 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `django_admin_log`
--
LOCK TABLES `django_admin_log` WRITE;
/*!40000 ALTER TABLE `django_admin_log` DISABLE KEYS */;
INSERT INTO `django_admin_log` VALUES (193,'2022-03-12 01:35:05.465349','44','test1',3,'',8,32),(192,'2022-03-12 00:55:03.725014','31','张三',3,'',6,32),(191,'2022-03-12 00:54:56.822759','1','色彩搭配挺好的!',3,'',11,32),(190,'2022-03-12 00:54:56.822759','2','好看!',3,'',11,32),(188,'2022-03-12 00:54:52.225579','1','[email protected]',3,'',26,32),(189,'2022-03-12 00:54:56.818757','3','不错啊!',3,'',11,32),(182,'2022-03-12 00:54:26.246498','32','admin',2,'[{\"changed\": {\"fields\": [\"Last login\", \"\\u6635\\u79f0\", \"\\u7528\\u6237\\u5934\\u50cf\"]}}]',6,32),(183,'2022-03-12 00:54:42.491638','30','9673022',3,'',6,32),(184,'2022-03-12 00:54:42.492639','29','2315F921A62F953AC048EF8EC251DF78',3,'',6,32),(185,'2022-03-12 00:54:42.492639','26','DDEB89044C7A261A4778EAB25D0BE1B1',3,'',6,32),(186,'2022-03-12 00:54:42.492639','24','E98D5D2EED06C2313CDD331E8BFA2421',3,'',6,32),(187,'2022-03-12 00:54:42.493639','2','fengfeng',3,'',6,32);
/*!40000 ALTER TABLE `django_admin_log` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `django_content_type`
--
DROP TABLE IF EXISTS `django_content_type`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `django_content_type` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`app_label` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`model` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `django_content_type_app_label_model_76bd3d3b_uniq` (`app_label`,`model`)
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `django_content_type`
--
LOCK TABLES `django_content_type` WRITE;
/*!40000 ALTER TABLE `django_content_type` DISABLE KEYS */;
INSERT INTO `django_content_type` VALUES (1,'admin','logentry'),(2,'auth','permission'),(3,'auth','group'),(4,'contenttypes','contenttype'),(5,'sessions','session'),(6,'app01','userinfo'),(7,'app01','advert'),(8,'app01','articles'),(9,'app01','avatars'),(10,'app01','cover'),(11,'app01','feedback'),(12,'app01','history'),(13,'app01','menuimg'),(14,'app01','myinfo'),(15,'app01','navcategory'),(16,'app01','new'),(17,'app01','site'),(18,'app01','tags'),(19,'app01','navs'),(20,'app01','moods'),(21,'app01','moodcomment'),(22,'app01','menu'),(23,'app01','comment'),(24,'app01','navtags'),(25,'app01','project'),(26,'api','email');
/*!40000 ALTER TABLE `django_content_type` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `django_migrations`
--
DROP TABLE IF EXISTS `django_migrations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `django_migrations` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`app` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`applied` datetime(6) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `django_migrations`
--
LOCK TABLES `django_migrations` WRITE;
/*!40000 ALTER TABLE `django_migrations` DISABLE KEYS */;
INSERT INTO `django_migrations` VALUES (1,'contenttypes','0001_initial','2022-01-02 11:13:02.936585'),(2,'contenttypes','0002_remove_content_type_name','2022-01-02 11:13:02.968614'),(3,'auth','0001_initial','2022-01-02 11:13:03.080715'),(4,'auth','0002_alter_permission_name_max_length','2022-01-02 11:13:03.096730'),(5,'auth','0003_alter_user_email_max_length','2022-01-02 11:13:03.101735'),(6,'auth','0004_alter_user_username_opts','2022-01-02 11:13:03.105738'),(7,'auth','0005_alter_user_last_login_null','2022-01-02 11:13:03.109742'),(8,'auth','0006_require_contenttypes_0002','2022-01-02 11:13:03.110742'),(9,'auth','0007_alter_validators_add_error_messages','2022-01-02 11:13:03.116748'),(10,'auth','0008_alter_user_username_max_length','2022-01-02 11:13:03.119750'),(11,'auth','0009_alter_user_last_name_max_length','2022-01-02 11:13:03.124755'),(12,'auth','0010_alter_group_name_max_length','2022-01-02 11:13:03.137768'),(13,'auth','0011_update_proxy_permissions','2022-01-02 11:13:03.141771'),(14,'auth','0012_alter_user_first_name_max_length','2022-01-02 11:13:03.145774'),(15,'app01','0001_initial','2022-01-02 11:13:03.907466'),(16,'admin','0001_initial','2022-01-02 11:13:03.970524'),(17,'admin','0002_logentry_remove_auto_add','2022-01-02 11:13:03.984537'),(18,'admin','0003_logentry_add_action_flag_choices','2022-01-02 11:13:03.995547'),(19,'sessions','0001_initial','2022-01-02 11:13:04.019570'),(20,'app01','0002_alter_userinfo_collects','2022-01-02 11:14:27.916624'),(21,'app01','0003_auto_20220118_1936','2022-01-18 11:37:08.154746'),(22,'app01','0004_articles_link','2022-01-21 11:05:05.744803'),(23,'app01','0005_auto_20220210_1832','2022-02-10 10:33:01.205010'),(24,'app01','0006_auto_20220213_1251','2022-02-13 04:51:50.607445'),(25,'app01','0007_auto_20220213_1254','2022-02-13 04:54:35.678082'),(26,'app01','0008_auto_20220213_1313','2022-02-13 05:13:05.140901'),(27,'app01','0009_auto_20220223_0814','2022-02-23 00:14:14.806527'),(28,'app01','0010_auto_20220223_1913','2022-02-23 11:13:04.801066'),(29,'app01','0011_auto_20220301_2013','2022-03-01 20:14:09.677811'),(30,'app01','0012_auto_20220301_2020','2022-03-01 20:20:44.540964'),(31,'app01','0013_userinfo_navs','2022-03-02 23:34:09.664855'),(32,'app01','0014_delete_myinfo','2022-03-06 09:58:55.305875'),(33,'app01','0015_delete_site','2022-03-06 09:59:12.745709'),(34,'app01','0016_delete_new','2022-03-06 09:59:38.128756'),(35,'app01','0017_project','2022-03-06 10:04:59.763792'),(36,'app01','0018_rename_a_unique_id_userinfo_token','2022-03-08 19:45:08.913190'),(37,'api','0001_initial','2022-03-11 21:32:08.491312'),(38,'api','0002_email_create_date','2022-03-11 21:36:42.767061'),(39,'app01','0019_userinfo_login_date','2022-03-11 21:51:52.859272'),(40,'app01','0020_remove_userinfo_login_date','2022-03-11 21:56:11.910685'),(41,'app01','0021_auto_20220311_2236','2022-03-11 22:36:13.284291'),(42,'app01','0022_auto_20220312_0932','2022-03-12 09:32:23.781565'),(43,'app01','0023_alter_moodcomment_addr','2022-03-12 09:51:33.322530');
/*!40000 ALTER TABLE `django_migrations` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `django_session`
--
DROP TABLE IF EXISTS `django_session`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `django_session` (
`session_key` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`session_data` longtext COLLATE utf8_unicode_ci NOT NULL,
`expire_date` datetime(6) NOT NULL,
PRIMARY KEY (`session_key`),
KEY `django_session_expire_date_a5c62663` (`expire_date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `django_session`
--
LOCK TABLES `django_session` WRITE;
/*!40000 ALTER TABLE `django_session` DISABLE KEYS */;
INSERT INTO `django_session` VALUES ('o52cc3m0g173jfd5ofow93kcatoain20','eyJ2YWxpZF9jb2RlIjoiaHI2bCJ9:1n6PSN:qOE0TTiRmjvV88mSz50kYZMwAFLc1E-rc0dcPz0whAY','2022-01-23 04:05:23.090555'),('cx8gf8ech9gchna433ysmhlwo4y9jhw1','eyJ2YWxpZF9jb2RlIjoiWEl1VyJ9:1n6RAq:BbeyGRJ1sS0ghrOBC9fwy58x7DD44eyOjyd3JXw98Yw','2022-01-23 05:55:24.748731'),('57msa6oem141b8yq1jxy3tulbzm97gdi','eyJ2YWxpZF9jb2RlIjoic1B3TiJ9:1n6WUg:HY_DmwzAjxxhYtG8ULNfhsV3qr3-7AO6uuf8boAKFYw','2022-01-23 11:36:14.823994'),('0z2vvtq89lnce8501v4vusjtogsfhqz0','eyJ2YWxpZF9jb2RlIjoiRDJRaCIsImVycm9yX2NvdW50IjowfQ:1nSKsG:l6l5FLZehjHRbFsnEUjvgQW8S1RpmfXId-5QhbWLzow','2022-03-24 23:38:44.504086'),('4b47dzyavwsfml6etou3nzh6egfv8gdj','.eJxVjEEOwiAQRe_C2hBgCgWX7j0DGRhGqoYmpV0Z765NutDtf-_9l4i4rTVuvSxxInEWRpx-t4T5UdoO6I7tNss8t3WZktwVedAurzOV5-Vw_w4q9vqtOTgMqNgYZwo60EOyWlvtlR8Iw5iQlQN0zgZFjMCaRw8IkCGrZEi8P8-NN44:1n7bUv:o3pL1anBMmVswVwqJbOpRr1DGRa7HGLu0bhz2UNq_LQ','2022-01-26 11:08:57.673949'),('ylk0lxncw2bzgkol9n09ll4itn2zsmi0','.eJxVjEEOwiAQRe_C2hBgCgWX7j0DGRhGqoYmpV0Z765NutDtf-_9l4i4rTVuvSxxInEWRpx-t4T5UdoO6I7tNss8t3WZktwVedAurzOV5-Vw_w4q9vqtOTgMqNgYZwo60EOyWlvtlR8Iw5iQlQN0zgZFjMCaRw8IkCGrZEi8P8-NN44:1n7FFu:Wfy8vuh0bLO8e8BtcLBDFRTWEq6O9g5qU76ZCbE4ujA','2022-01-25 11:23:58.234518'),('f2qtevoyiv5yp0v16fg00t5s0q6pi2af','.eJxVjDkOgzAUBe_iOrI-GBs7ZXqkSDmA9RccSFgkljRR7h6QaGhn5r2v-mDXSuRRanVV9756qIuKuC5NXOd6iq1s2J8ZIb_rYRfywuE5ah6HZWpJ74k-7Kyr7bO7He3poMG52dYGsUBb5sYnFsBMyFgHtiSXCJNkBbLzYjIKiU3wARLkwTCEEiCQs-r3B31tPiM:1n6tGK:1NQ3ZJ1d00qkDfvNrOyBAOANKQVg5_CL0HquA1ekqbg','2022-01-24 11:54:56.857948'),('87qq8hu3r67ghmhaf1yryafqj9gtiz2i','.eJxVjLsOgzAMAP8lcxU1xITQsTtS5y6R7RhCi4LEo0vVfy9ILKx3p_uqDw59DDxGUTeVusdTXVTAdUlhnWUKfdywsWdIyG_Ju4kvzN2oeczL1JPeE33YWTfbdLgf7WmQcE7715jqigAWKgR25EpqxVBE54iqQsALOO8KqaEUsN56bm1h6miYqeRW_f6V3j50:1nCMIk:feb8I6NDkbNZGdq7KA93JdreqBKVBS2iLy52oKOgREE','2022-02-08 13:56:02.954934'),('v5oa84s6fackw1r57mwl8chyg2dju2lr','.eJzFl9uO2yAQhl8l4jq78QEMzl3bZ6hUtV5FmEPi1ocI25GqVd69gHe7CnUXBzXpFQ7ze_D_MRnjZ3CidcV3rOMCbMGXr4efYA2EUp3Sc2M7gG20Bjs6Dofd2Au1q7iWJeBirqTsh2hNgB6PUfxoUz6a-OOnsR-65uOL4OKuA-0PJheOcgwlTPOUI8IxTBBECU1ykos4KjkhSMSS0TRGSUpLkjOI4lSinJEMstI-SiPasde5vj0XoKWNKMB2VYAP5mEKsNaXFevaaVJStZL0gVWK1WIKNtp73Zvw5f1FMSKBpRkgpAsSjaqeYhvKm6rdWBr6-iTUsJkklPPP76l0_EVZKkE5U2NTzjzaEmvn9SrczvnJhEXFTTSOomQmW4YI1gOmIgqHo4ZKS3ovnlfdbQEtt-QCSj3ZNHWmn6gYc5wlwbhYp6vEx2oS3Q_UNdZcbNCbOyOR_VViEYxtoHtvhVnNPaEtN-ZCQzO5MUqISZqkOBiTactVKzsfqt-62-JabskFlHmy6YpNGTcVmxMSjEsKwc2r7w9c7VjX94ByjQ0XEfbnzlNohojJ8PZ-ogNV_u7-IrtfPV1jz0VH5nJTnpshKs1AIsbMSlkWjs6caXzcrObG0AKNudDyq3LrfclkeL83XKpmvwSfkf0vgotcOiDjaG4JieK3lVApzRIkScIPrS09ef-1VnNjdoHGXGjxTG5SMmiHMhwT6xpdRN7D_avstrCWG3LxzJ3uc4Jt2WZC2EGa3olinAbDOqruu2BeWK-y28IKteeiS91GN19qdNoZFtvPL2JbQErs6wjDmTV7s2Z_qETNH2g9eD9UsdB7P5_FnNb6B9bt_7I3-oN8s1fdeHxnY940C3fl35ie6wiLjLq7hNwJeH4C51-wHTq-:1nRDMz:I1k-ugI-R_eNo5d-BPINGd7j7GN1m60zBx-K36BvGcE','2022-03-21 21:25:49.878869'),('sts5e9xgzkaph2vlbzfi8muyi6nv6jc1','eyJlcnJvcl9sb2dpbiI6MCwidmFsaWRfY29kZSI6IjRIV20ifQ:1nQV34:cMEEy6LXhejK7pxD9HaknydavF0fR0AVbGs-JL9haAk','2022-03-19 22:06:18.413504'),('nxlha1ta3wdfxr3wxbman1u742flvr6b','.eJxVjEEOwiAQRe_C2hBgCgWX7j0DGRhGqoYmpV0Z765NutDtf-_9l4i4rTVuvSxxInEWRpx-t4T5UdoO6I7tNss8t3WZktwVedAurzOV5-Vw_w4q9vqtOTgMqNgYZwo60EOyWlvtlR8Iw5iQlQN0zgZFjMCaRw8IkCGrZEi8P8-NN44:1nJ7aw:mncWQfTvcgW4ri5YKJRlG_UPy3-jvTETPuYz2yDfyaY','2022-02-27 05:38:46.296808'),('1a8g2kse04c3ex1iegt149fdqb4e7zgl','.eJxVjMsOwiAQRf-FtSHQwnRw6d5vIDM8pGogKe3K-O_apAvd3nPOfQlP21r81tPi5yjOYgBx-h2ZwiPVncQ71VuTodV1mVnuijxol9cW0_NyuH8HhXr51lbrKSOQIQSwEYCcQRM5AergxlExZ-u00SojRp2MgpAxKzZpcBOTeH8A7xQ3ug:1nJ7Zr:HCyeLSlL5Wqm9_WVAOJgDZVXjg5cdqYQwYzyklK2kTI','2022-02-27 05:37:39.579933'),('2ia83yodgw8mljt8xw08eqv7u92a9hpt','.eJxVjD0PgjAURf9LZ9O0fVCoo5uDu3FpbvtaQQkkfLgY_7uQsLCec-79ig-6ln0cOImzuI-PqzgJj2Vu_DKl0be8YnNkAfGd-k3wC_1zkHHo57ENckvkbid5Wz-7y94eDhpMzbrOzsJBZWOsSbCki1BqXepa1QXDVQFZWYK1pVOcQVnnqiYQRYoqGBa_P2EGPfM:1nD5fh:hAJJAg255EZxsze0wuL-RIeOIYMmNHBVScxTqkPuF8g','2022-02-10 14:22:45.900916'),('1952q7m3ndlurphui7zu4v6ypa8n5hy4','.eJzFl9tS2zAQhl-F8TUQWT5I5o72GXrVMMxaWiVqfcj4kBsm717JgQLCIKOS9God7e-V_08bWX6I7mEctvdjj929ltFNlNDo8uVgCeI3NjYDux2Jr_dQaXlt89ffx35o62-Pgld3baHfmlu4jBPORMaTghPKc4BCESR5kaUUgCEpSpRpYQSKZxRoUQgGwCUykSSUKlu0xmbsTa2fD-uogRrX0c3FOrrd6XV0aS60aJvjkILuQsGV0J2o8JisW4lVb9Ov716vx4IAmpCiyk3IEhlPgyReUHbsqmNuBbLWzQp2eoU16Gp1zIOUP96VmOSjrOwQpOjGupx5RL_Bw-XFV5k63Nk0ammzMSHUHYjdyW5tM_zbCmTIlA1pCkHMzQOY6z12w0fYX6gWk_dbm2G_3I4LN52plmecmcAASTicbtBG0nvxPOlOC2i5JRdQ5qlmqAsytTrLaTAu0Zou8bE6is4H6jPWXGy5t3bOyfSrZBiMbYCNt8MmzTmhLTfmQmMztVlGuS1KExaMyb4WdaNaH6q_utPiWm7JBcQ91ex7R0jbsQXnwbgUorRHjze4mrGqzgHlMzZcRIW_dpGkNhChwrf3PQzQ-Xf3R9n5-ukz9hx0MZmrDbKwgZQ2cCKEnSnPw9HZM6WP26Q5MbRAYy60N6ezD2ubdclV-H5vueh6swSflf0vgotcuiDp3BQqi59nykplp-CUhh9aG9h7_7WT5sTsAo250JKZ2rwU6RTKcEyirU0TeQ_3T7LTwlpuyMUzd7ovOJvaNkecgrJ7ZxazJBjWrmt_ofDCepKdFlaoPRdd5r5Y51sNjisj4unzi09bQMKn1xFLZ-bs7Zz9VmMlr6AavB-qDM3az1exp7X-SrSbd9ZmHLarTdeOuw8W5lmzcFW-xvTcjrDIqLtKzB3ID3fR4Q9BNqU_:1nSjAK:QErGjP_fnfrFigPMScN8dXsuAyZ5ZO0oWCJlkLYO0TM','2022-03-26 01:35:00.699015'),('l3973jsnkcgdxp0aod510eur3ng51g1k','.eJxVjDsOgzAQBe-yNUK7YBNMSdrcwdr1R6AkgAxOE-XugSgN7byZ94YXP0Zv3ewDdLD0twwFhJTmtLM8bdBhAZbzNti8hmRHv2s1wQkKu3uYjoWXBan8fZbHXl7zus3P_i-cqoHXYU8oKI7YcIxGRAi9RmUccqhaJRdqW2KJ0ngxdWAlMQpio5C01sZViPD5AsDkP9c:1nSfk9:bK7PSNoH8ET3TNY595RhFxo5z1R2jm9wKo7YiJGkpYw','2022-03-25 21:55:45.786191'),('tew37vxtgnjvk70pyftf18j97q1ce6aq','.eJzFl9tS2zAQhl-F8TUQWT5I5o72GXrVMMxaWiVqfcj4kBsm717JgQLCIKOS9God7e-V_08bWX6I7mEctvdjj929ltFNlNDo8uVgCeI3NjYDux2Jr_dQaXlt89ffx35o62-Pgld3baHfmlu4jBPORMaTghPKc4BCESR5kaUUgCEpSpRpYQSKZxRoUQgGwCUykSSUKlu0xmbsTa2fD-uogRrX0c3FOrrd6XV0aS60aJvjkILuQsGV0J2o8JisW4lVb9Ov716vx4IAmpCiyk3IEhlPgyReUHbsqmNuBbLWzQp2eoU16Gp1zIOUP96VmOSjrOwQpOjGupx5RL_Bw-XFV5k63Nk0ammzMSHUHYjdyW5tM_zbCmTIlA1pCkHMzQOY6z12w0fYX6gWk_dbm2G_3I4LN52plmecmcAASTicbtBG0nvxPOlOC2i5JRdQ5qlmqAsytTrLaTAu0Zou8bE6is4H6jPWXGy5t3bOyfSrZBiMbYCNt8MmzTmhLTfmQmMztVlGuS1KExaMyb4WdaNaH6q_utPiWm7JBcQ91ex7R0jbsQXnwbgUorRHjze4mrGqzgHlMzZcRIW_dpGkNhChwrf3PQzQ-Xf3R9n5-ukz9hx0MZmrDbKwgZQ2cCKEnSnPw9HZM6WP26Q5MbRAYy60N6ezD2ubdclV-H5vueh6swSflf0vgotcuiDp3BQqi59nykplp-CUhh9aG9h7_7WT5sTsAo250JKZ2rwU6RTKcEyirU0TeQ_3T7LTwlpuyMUzd7ovOJvaNkecgrJ7ZxazJBjWrmt_ofDCepKdFlaoPRdd5r5Y51sNjisj4unzi09bQMKn1xFLZ-bs7Zz9VmMlr6AavB-qDM3az1exp7X-SrSbd9ZmHLarTdeOuw8W5lmzcFW-xvTcjrDIqLtKzB3ID3fR4Q9BNqU_:1nSiXx:-go2DaF_B5Vz-91uZANXFoklWOflpW1Mu89u882XzVQ','2022-03-26 00:55:21.340021'),('ddwneeoapnknyr9tazvcb4ng1115f65o','.eJzFl9tS2zAQhl-F8TUQWT5I5o72GXrVMMxaWiVqfcj4kBsm717JgQLCIKOS9God7e-V_08bWX6I7mEctvdjj929ltFNlNDo8uVgCeI3NjYDux2Jr_dQaXlt89ffx35o62-Pgld3baHfmlu4jBPORMaTghPKc4BCESR5kaUUgCEpSpRpYQSKZxRoUQgGwCUykSSUKlu0xmbsTa2fD-uogRrX0c3FOrrd6XV0aS60aJvjkILuQsGV0J2o8JisW4lVb9Ov716vx4IAmpCiyk3IEhlPgyReUHbsqmNuBbLWzQp2eoU16Gp1zIOUP96VmOSjrOwQpOjGupx5RL_Bw-XFV5k63Nk0ammzMSHUHYjdyW5tM_zbCmTIlA1pCkHMzQOY6z12w0fYX6gWk_dbm2G_3I4LN52plmecmcAASTicbtBG0nvxPOlOC2i5JRdQ5qlmqAsytTrLaTAu0Zou8bE6is4H6jPWXGy5t3bOyfSrZBiMbYCNt8MmzTmhLTfmQmMztVlGuS1KExaMyb4WdaNaH6q_utPiWm7JBcQ91ex7R0jbsQXnwbgUorRHjze4mrGqzgHlMzZcRIW_dpGkNhChwrf3PQzQ-Xf3R9n5-ukz9hx0MZmrDbKwgZQ2cCKEnSnPw9HZM6WP26Q5MbRAYy60N6ezD2ubdclV-H5vueh6swSflf0vgotcuiDp3BQqi59nykplp-CUhh9aG9h7_7WT5sTsAo250JKZ2rwU6RTKcEyirU0TeQ_3T7LTwlpuyMUzd7ovOJvaNkecgrJ7ZxazJBjWrmt_ofDCepKdFlaoPRdd5r5Y51sNjisj4unzi09bQMKn1xFLZ-bs7Zz9VmMlr6AavB-qDM3az1exp7X-SrSbd9ZmHLarTdeOuw8W5lmzcFW-xvTcjrDIqLtKzB3ID3fR4Q9BNqU_:1nXN49:tZqHQFuixzVQk0BQ9W7VyMlF5USM_AE76jVunULk-jU','2022-04-07 20:59:49.623498'),('hymi0fnmcjbzio2qkyiq3yww1ra8eer2','.eJxVjEEOgjAQRe8ya0JKC3TKUr2AG7fN0A6BqJQU6sZ4d4txw_b99_4bXvSYvHXBM3Rwu1x7KIBjDDGzNG_QiQIspW20aeVoJ581JeEAe3J3nveFlkVU5e-z3PfynNYtPE9_4VCNtI45QV8p1K5BZVBIbInMIFi0pqklkWZheva1ycKAjSRpjNNE6Fk7paQc4PMFaOk_BA:1nomar:Z2vOdAFoWtBji1L9F7bYNpPHxjU7wvrXDzWaHfZrxhU','2022-05-25 21:41:33.506346');
/*!40000 ALTER TABLE `django_session` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2022-05-11 23:40:01