Python 21 Django 实用小案例1

实用案例

     验证码与验证

   KindEditor

     组合搜索的实现

   单例模式

     beautifulsoup4

     

验证码与验证

需要安装Pillow模块

pip stall pillow

1、首先需要借助pillow模块用来画一个验证码图形,这里单独封装了一个py文件,调用一个方法就好了

 1 #!/user/bin/env python
 2 # -*-coding: utf-8-*-
 3 import random
 4 from PIL import ImageDraw,ImageFont,Image,ImageFilter
 5 
 6 
 7 def random_check_code(width=120, height=30, char_length=5, font_file='wryh.ttf', font_size=28):
 8     code = []
 9     img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
10     draw = ImageDraw.Draw(img, mode='RGB')
11 
12     def rndChar():
13         """
14         生成随机字母
15         :return:
16         """
17         return chr(random.randint(65, 90))
18 
19     def rndColor():
20         """
21         生成随机颜色
22         :return:
23         """
24         return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
25 
26     # 写文字
27     font = ImageFont.truetype(font_file, font_size)
28     for i in range(char_length):
29         char = rndChar()
30         code.append(char)
31         h = random.randint(0, 4)
32         draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
33 
34     # 写干扰点
35     for i in range(40):
36         draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
37 
38     # 写干扰圆圈
39     for i in range(40):
40         draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
41         x = random.randint(0, width)
42         y = random.randint(0, height)
43         draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
44 
45     # 画干扰线
46     for i in range(5):
47         x1 = random.randint(0, width)
48         y1 = random.randint(0, height)
49         x2 = random.randint(0, width)
50         y2 = random.randint(0, height)
51         draw.line((x1, y1, x2, y2), fill=rndColor())
52 
53     img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) #加滤镜,可以增加颜色的不同
54     return img, ''.join(code)
生成随机验证码

函数的参数都已在调用的时候修改。

2、登陆界面设计

假设验证码跟登录页面在同一函数一起生成,那么每次刷新验证码都需要整个页面一起重新加载;显然,这是不合理的。所以可以确定验证码跟登录界面是2个视图函数控制的。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body style="margin: 0 auto;">
 8     <div id="main">
 9         <form method="post" action="/login/">
10             {% csrf_token %}
11             <p><label>用户名:</label><input type="text" name="user" /></p>
12             <p><label>密码:</label><input type="password" name="pwd" /></p>
13             <p><label>验证码:</label><input type="text" name="checkcode" /><img src="/check_code.html" /></p>
14             <p><input type="submit" /></p>
15         </form>
16     </div>
17 </body>
18 </html>
login html
1 def login(request):
2     if request.method == 'GET':
3         return  render(request, 'login.html')
login 视图函数

3、验证码

将验证码图片对象返回到模板

1 def check_code(request):
2     stream = BytesIO()  # 申请一段内存
3     img, code = random_check_code()  # 获取随机码跟随机码图片对象
4     img.save(stream, 'PNG')  # 将随机码对象保存到内存对象中
5     request.session['CheckCode'] = code  # 将随机字符串保存到session
6     return HttpResponse(stream.getvalue())  # 返回内存中的随机码图片对象
View Code

4、如何刷新验证码呢

直接将原路由系统通过点击事件赋值给src,浏览器默认是不会进行刷新的;所以这里有一个小技巧,我们可以获取src的值,在末尾加上一个?,这样就可以实现点击刷新了。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body style="margin: 0 auto;">
 8     <div id="main">
 9         <form method="post" action="/login/">
10             {% csrf_token %}
11             <p><label>用户名:</label><input type="text" name="user" /></p>
12             <p><label>密码:</label><input type="password" name="pwd" /></p>
13             <p><label>验证码:</label><input type="text" name="checkcode" /><img src="/check_code.html" οnclick="ImgChange(this);"/></p>
14             <p><input type="submit" /></p>
15         </form>
16     </div>
17 </body>
18 <script>
19     function ImgChange(ths) {
20         ths.src = ths.src + '?'
21     }
22 </script>
23 </html>
修改过的login html

开启验证码验证功能

 1 def login(request):
 2     if request.method == 'GET':
 3         return  render(request, 'login.html')
 4     elif request.method == 'POST':
 5         checkcode = request.POST.get('checkcode')
 6         code_session = request.session['CheckCode']
 7         print(checkcode)
 8         print(code_session)
 9         if checkcode.upper() == request.session['CheckCode'].upper():
10             return HttpResponse('验证成功')
11         else:
12             return render(request, 'login.html')
修改后的login 视图函数

 

 

KindEditor

1、官网下载

http://kindeditor.net/demo.php

2、文件夹解压文件说明

├── asp                          asp示例
├── asp.net                    asp.net示例
├── attached                  空文件夹,放置关联文件attached
├── examples                 HTML示例
├── jsp                          java示例
├── kindeditor-all-min.js 全部JS(压缩)
├── kindeditor-all.js        全部JS(未压缩)
├── kindeditor-min.js      仅KindEditor JS(压缩)
├── kindeditor.js            仅KindEditor JS(未压缩)
├── lang                        支持语言
├── license.txt               License
├── php                        PHP示例
├── plugins                    KindEditor内部使用的插件
└── themes                   KindEditor主题

3、基本使用

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <div style="margin: 0 auto; width: 500px;height: 300px;">
 9         <textarea id="content"></textarea>
10     </div>
11 
12     <script src="/static/jquery-3.2.1.js"></script>
13     <script src="/static/kindeditor/kindeditor-all-min.js"></script>
14     <script>
15         $(function() {
16             KindEditor.create("#content", {
17                 width: '400px',
18                 height: '200px'
19 
20             })
21         })
22     </script>
23 </body>
24 </html>
View Code

4、详细参数

http://kindeditor.net/docs/option.html

5、上传文件示例

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form action="/upload_kind/" method="post">
 9 
10         <div style="margin: 0 auto; width: 500px;height: 300px;">
11             <textarea id="content"></textarea>
12         </div>
13     </form>
14     <script src="/static/jquery-3.2.1.js"></script>
15     <script src="/static/kindeditor/kindeditor-all-min.js"></script>
16     <script>
17         $(function() {
18             KindEditor.create("#content", {
19                 width: '400px',
20                 height: '200px',
21                 extraFileUploadParams:{'csrfmiddlewaretoken':"{{ csrf_token }}"},
22                 uploadJson:'/upload_img/',
23                 fileManagerJson: '/upload_file_manage/',
24                 allowImageUpload: true,
25                 allowFileManager:true
26             })
27         })
28     </script>
29 </body>
30 </html>
html
 1 def upload_img(request):
 2     f = request.FILES.get('imgFile')
 3     import os
 4     path = os.path.join("static/images", f.name)
 5     with open(path, 'wb') as file_obj:
 6         for chunck in f.chunks():
 7             file_obj.write(chunck)
 8     import json
 9     dic = {
10         'error': 0,
11         'url': '/' + path,
12         'message': '错误了...'
13     }
14     return HttpResponse(json.dumps(dic))
15 
16 def upload_file_manage(request):
17     import os,time,json
18     dic = {}
19     root_path = 'C:/Users/Administrator/Desktop/DownTimeAnalysis/static/'
20     static_root_path = '/static/'
21     request_path = request.GET.get('path')
22     if request_path:
23         abs_current_dir_path = os.path.join(root_path, request_path)
24         move_up_dir_path = os.path.dirname(request_path.rstrip('/'))
25         dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path
26 
27     else:
28         abs_current_dir_path = root_path
29         dic['moveup_dir_path'] = ''
30 
31     dic['current_dir_path'] = request_path
32     dic['current_url'] = os.path.join(static_root_path, request_path)
33 
34     file_list = []
35     for item in os.listdir(abs_current_dir_path):
36         abs_item_path = os.path.join(abs_current_dir_path, item)
37         a, exts = os.path.splitext(item)
38         is_dir = os.path.isdir(abs_item_path)
39         if is_dir:
40             temp = {
41                 'is_dir': True,
42                 'has_file': True,
43                 'filesize': 0,
44                 'dir_path': '',
45                 'is_photo': False,
46                 'filetype': '',
47                 'filename': item,
48                 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
49             }
50         else:
51             temp = {
52                 'is_dir': False,
53                 'has_file': False,
54                 'filesize': os.stat(abs_item_path).st_size,
55                 'dir_path': '',
56                 'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False,
57                 'filetype': exts.lower().strip('.'),
58                 'filename': item,
59                 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path)))
60             }
61 
62         file_list.append(temp)
63     dic['file_list'] = file_list
64     return HttpResponse(json.dumps(dic))
View

路由系统

    url(r'^kind/$', views.kind),url(r'^upload_img/', views.upload_img),  # 前面有一个kind,视图函数可以获取参数dir来区分是文件还是其他。url(r'^upload_file_manage/', views.upload_file_manage),

 

 

6、XSS过滤特殊标签

处理依赖

pip3 install beautifulsoup4
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from bs4 import BeautifulSoup
 4 
 5 
 6 class XSSFilter(object):
 7     __instance = None
 8 
 9     def __init__(self):
10         # XSS白名单
11         self.valid_tags = {
12             "font": ['color', 'size', 'face', 'style'],
13             'b': [],
14             'div': [],
15             "span": [],
16             "table": [
17                 'border', 'cellspacing', 'cellpadding'
18             ],
19             'th': [
20                 'colspan', 'rowspan'
21             ],
22             'td': [
23                 'colspan', 'rowspan'
24             ],
25             "a": ['href', 'target', 'name'],
26             "img": ['src', 'alt', 'title'],
27             'p': [
28                 'align'
29             ],
30             "pre": ['class'],
31             "hr": ['class'],
32             'strong': []
33         }
34 
35     @classmethod
36     def instance(cls):
37         if not cls.__instance:
38             obj = cls()
39             cls.__instance = obj
40         return cls.__instance
41 
42     def process(self, content):
43         soup = BeautifulSoup(content, 'lxml')
44         # 遍历所有HTML标签
45         for tag in soup.find_all(recursive=True):
46             # 判断标签名是否在白名单中
47             if tag.name not in self.valid_tags:
48                 tag.hidden = True
49                 if tag.name not in ['html', 'body']:
50                     tag.hidden = True
51                     tag.clear()
52                 continue
53             # 当前标签的所有属性白名单
54             attr_rules = self.valid_tags[tag.name]
55             keys = list(tag.attrs.keys())
56             for key in keys:
57                 if key not in attr_rules:
58                     del tag[key]
59 
60         return soup.renderContents()
61 
62 
63 if __name__ == '__main__':
64     html = """<p class="title">
65                         <b>The Dormouse's story</b>
66                     </p>
67                     <p class="story">
68                         <div name='root'>
69                             Once upon a time there were three little sisters; and their names were
70                             <a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a>
71                             <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
72                             <a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>;
73                             and they lived at the bottom of a well.
74                             <script>alert(123)</script>
75                         </div>
76                     </p>
77                     <p class="story">...</p>"""
78 
79     v = XSSFilter.instance().process(html)
80     print(v)
XSS 示例
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from bs4 import BeautifulSoup
 4 
 5 
 6 class XSSFilter(object):
 7     __instance = None
 8 
 9     def __init__(self):
10         # XSS白名单
11         self.valid_tags = {
12             "font": ['color', 'size', 'face', 'style'],
13             'b': [],
14             'div': [],
15             "span": [],
16             "table": [
17                 'border', 'cellspacing', 'cellpadding'
18             ],
19             'th': [
20                 'colspan', 'rowspan'
21             ],
22             'td': [
23                 'colspan', 'rowspan'
24             ],
25             "a": ['href', 'target', 'name'],
26             "img": ['src', 'alt', 'title'],
27             'p': [
28                 'align'
29             ],
30             "pre": ['class'],
31             "hr": ['class'],
32             'strong': []
33         }
34 
35     def __new__(cls, *args, **kwargs):
36         """
37         单例模式
38         :param cls:
39         :param args:
40         :param kwargs:
41         :return:
42         """
43         if not cls.__instance:
44             obj = object.__new__(cls, *args, **kwargs)
45             cls.__instance = obj
46         return cls.__instance
47 
48     def process(self, content):
49         soup = BeautifulSoup(content, 'lxml')
50         # 遍历所有HTML标签
51         for tag in soup.find_all(recursive=True):
52             # 判断标签名是否在白名单中
53             if tag.name not in self.valid_tags:
54                 tag.hidden = True
55                 if tag.name not in ['html', 'body']:
56                     tag.hidden = True
57                     tag.clear()
58                 continue
59             # 当前标签的所有属性白名单
60             attr_rules = self.valid_tags[tag.name]
61             keys = list(tag.attrs.keys())
62             for key in keys:
63                 if key not in attr_rules:
64                     del tag[key]
65 
66         return soup.renderContents()
67 
68 
69 if __name__ == '__main__':
70     html = """<p class="title">
71                         <b>The Dormouse's story</b>
72                     </p>
73                     <p class="story">
74                         <div name='root'>
75                             Once upon a time there were three little sisters; and their names were
76                             <a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a>
77                             <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
78                             <a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>;
79                             and they lived at the bottom of a well.
80                             <script>alert(123)</script>
81                         </div>
82                     </p>
83                     <p class="story">...</p>"""
84 
85     obj = XSSFilter()
86     v = obj.process(html)
87     print(v)
基于__new__实现单例模式示例

7、保存

直接form提交,视图函数接收对应的textarea的name就好了。

1 def upload_kind(request):
2     print(request.POST.get('content'))
3     return HttpResponse('ok')
View

 

 

组合搜索

大家一定对上面这张图不陌生,这就是一个很经典的组合搜索。

下面我们来做一个简单的搜索。

 1 class ArticleType(models.Model):
 2     caption = models.CharField(max_length=32)
 3 
 4 
 5 class Category(models.Model):
 6     name = models.CharField(max_length=32)
 7 
 8 
 9 class Article(models.Model):
10     title = models.CharField(max_length=32)
11     content = models.CharField(max_length=255)
12     category = models.ForeignKey(to='Category')
13     article_type = models.ForeignKey(to='ArticleType')
models.py
HTML
1 def article(request, *args, **kwargs):
2     result = models.Article.objects.all()
3     return render(request, 'article.html', {'result':result})
View

去数据库补充点数据,然后就可以运行了。

先把所有的选择项列出来。

 1 <h1>过滤条件</h1>
 2 <div class="condition-div">
 3     <div><a>全部</a>
 4     {% for row in article_type %}#}
 5     <a>{{ row.caption }}</a>
 6     {% endfor %}#}
 7     </div>
 8     <div><a>全部</a>
 9     {% for row in category%}#}
10     <a>{{ row.name}}</a>
11     {% endfor %}#}
12     </div>
13 </div>
HTML
 1 def article(request, *args, **kwargs):
 2     article_type_list = models.ArticleType.objects.all()
 3     category = models.Category.objects.all()
 4     result = models.Article.objects.all()
 5     return render(
 6         request,
 7         "article.html",
 8         {
 9             "result": result,
10             "article_type": article_type_list,
11             "category": category
12         }
13     )
view

这时候再来好好研究一下网页的逻辑

点完SUV,跳到了SUV的页面,对SUV进行删选,但是后面还有一串字符,-0-1-1等等,不难发现这是用正则做的路由参数,加上p可以固定不同的类型对应不同的位置参数。

    url(r'^article-(?P<article_type_id>\d+)-(?P<category_id>\d+).html', views.article),

但是,还有一个问题,比如选择了能源为汽油,又要选择座位来组合怎么做呢?

首先,需要先记录下当前的筛选参数,当然,url已经做到了,所以我们修改下URL

    url(r'^article-(?P<article_type_id>\d+)-(?P<category_id>\d+).html', views.article, name='article'),

看到name,大家一定记起来了,这里运用到了反转,记录动态URL。先记录下url里面的参数,再把参数传递给前台,告诉前台,那么做能源筛选的时候,是不是可以直接生成一个url,记录下所有其他选择的标签的参数,再加入自身的id。上代码:

 1 def article(request, *args, **kwargs):
 2     # from django.urls import reverse
 3     # url = reverse('article', kwargs=kwargs)
 4     # print(url)  # 强行带了波url的节奏,其实并不需要用到,因为url传过来的id已经被处理成字典形式了,可以区分开的。我们拿到**kwargs
 5     condition = {}
 6     for k, v in kwargs.items():
 7         kwargs[k] = int(v)
 8         if v == '0':
 9             pass
10         else:
11             condition[k] = v  #这里的逻辑是因为全部这个标签,数据库的类别ID是自增的,所以设置0是最保险的。在后台把所有为0的全部过滤掉,不然会查询不到数据的。
12     article_type_list = models.ArticleType.objects.all()
13     category = models.Category.objects.all()
14     # result = models.Article.objects.filter(article_type_id=1, category_id=2)
15     result = models.Article.objects.filter(**condition)
16     return render(
17         request,
18         "article.html",
19         {
20             "result": result,
21             "article_type": article_type_list,
22             "category": category,
23             "arg_dict": kwargs,
24         }
25     )
View
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <style>
 7         .condition-div a{
 8             display: inline-block;
 9             padding: 2px 3px;
10             margin: 3px 5px;
11             border: 1px solid slategrey;
12         }
13         .condition-div a.active{
14             background-color: lightslategrey;
15         }
16     </style>
17 </head>
18 <body>
19     <h1>过滤条件</h1>
20     <div class="condition-div">
21         <div>
22             {% if arg_dict.article_type_id == 0 %}
23                 <a class="active" href="/app01/article-0-{{ arg_dict.category_id }}.html">全部</a>
24             {% else %}
25                 <a href="/app01/article-0-{{ arg_dict.category_id }}.html">全部</a>
26             {% endif %}
27             {% for row in article_type %}
28                 {% if row.id == arg_dict.article_type_id %}
29                     <a class="active" href="/app01/article-{{ row.id }}-{{ arg_dict.category_id }}.html">{{ row.caption }}</a>
30                 {% else %}
31                        <a href="/app01/article-{{ row.id }}-{{ arg_dict.category_id }}.html">{{ row.caption }}</a>
32                 {% endif %}
33             {% endfor %}
34 {#            {% filter_article_type article_type arg_dict %}#}
35         </div>
36         <div>
37 
38             {% if arg_dict.category_id == 0 %}
39                 <a class="active" href="/app01/article-{{ arg_dict.article_type_id }}-0.html">全部</a>
40             {% else %}
41                 <a href="/app01/article-{{ arg_dict.article_type_id }}-0.html">全部</a>
42             {% endif %}
43             {% for row in category %}
44                 {% if row.id == arg_dict.category_id %}
45                     <a class="active" href="/app01/article-{{ arg_dict.article_type_id }}-{{ row.id }}.html">{{ row.name }}</a>
46                 {% else %}
47                     <a href="/app01/article-{{ arg_dict.article_type_id }}-{{ row.id }}.html">{{ row.name }}</a>
48                 {% endif %}
49             {% endfor %}
50         </div>
51     </div>
52 
53     <h1>查询结果</h1>
54     <ul>
55         {% for row in result %}
56             <li>{{ row.od }} - {{ row.title }}</li>
57         {% endfor %}
58     </ul>
59 
60 </body>
61 </html>
html

这时候基本上就已经做好了,前台html里面的if else就不具体说了,主要就是加一个active class.

现在这个前台看着太乱了,就是要强行少代码,怎么办?大家一定觉得很夸张。。。怎么减代码??一脸懵逼,二脸懵逼,三脸懵逼。。。。。。

给大家体个醒,simple_tag,你一定会激动地叫起来,喔~~

刚好复习一下simple_tag 的制作思路,首先项目里面建一个templatetags文件夹,里面新建任意一个py文件。

 1 #!/user/bin/env python
 2 # -*-coding: utf-8-*-
 3 from django import template
 4 from django.utils.safestring import mark_safe
 5 register = template.Library()
 6 
 7 
 8 
 9 @register.simple_tag
10 def filter_all(arg_dict, k):
11     if k == 'article_type_id':
12         n1 = arg_dict['article_type_id']
13         n2 = arg_dict['category_id']
14         if  n1 == 0:
15             ret = '<a class="active" href="/app01/article-0-%s.html">全部</a>' % n2
16         else:
17             ret = '<a href="/app01/article-0-%s.html">全部</a>' % n2
18     else:
19         n1 = arg_dict['category_id']
20         n2 = arg_dict['article_type_id']
21         if  n1 == 0:
22             ret = '<a class="active" href="/app01/article-%s-0.html">全部</a>' % n2
23         else:
24             ret = '<a href="/app01/article-%s-0.html">全部</a>' % n2
25     return mark_safe(ret)
26 
27 @register.simple_tag
28 def filter_article_type(article_type, arg_dict):
29     '''
30     {% for row in article_type %}
31                 {% if row.id == arg_dict.article_type_id %}
32                     <a class="active" href="/app01/article-{{ row.id }}-{{ arg_dict.category_id }}.html">{{ row.caption }}</a>
33                 {% else %}
34                        <a href="/app01/article-{{ row.id }}-{{ arg_dict.category_id }}.html">{{ row.caption }}</a>
35                 {% endif %}
36             {% endfor %}
37     :return:
38     '''
39     ret = []
40     for row in article_type:
41         if row.id == arg_dict['article_type_id']:
42             temp = '<a class="active" href="/app01/article-%s-%s.html">%s</a>' % \
43                    (row.id, arg_dict['category_id'], row.caption)
44         else:
45             temp = '<a href="/app01/article-%s-%s.html">%s</a>' % (row.id, arg_dict['category_id'], row.caption)
46         ret.append(temp)
47     return mark_safe(''.join(ret))
48 
49 
50 @register.simple_tag
51 def filter_category(category, arg_dict):
52     '''
53     {% for row in category %}
54         {% if row.id == arg_dict.category_id %}
55             <a class="active" href="/app01/article-{{ arg_dict.article_type_id }}-{{ row.id }}.html">{{ row.name }}</a>
56         {% else %}
57             <a href="/app01/article-{{ arg_dict.article_type_id }}-{{ row.id }}.html">{{ row.name }}</a>
58         {% endif %}
59     {% endfor %}
60     :return:
61     '''
62     ret = []
63     for row in category:
64         if row.id == arg_dict['category_id']:
65             temp = '<a class="active" href="/app01/article-%s-%s.html">%s</a>' % \
66                    (arg_dict['article_type_id'], row.id, row.name)
67         else:
68             temp = '<a href="/app01/article-%s-%s.html">%s</a>' % \
69                    (arg_dict['article_type_id'], row.id, row.name)
70         ret.append(temp)
71     return mark_safe(''.join(ret))
simple_tag
 1 {% load filter %}
 2 <!DOCTYPE html>
 3 <html lang="en">
 4 <head>
 5     <meta charset="UTF-8">
 6     <title>Title</title>
 7     <style>
 8         .condition-div a{
 9             display: inline-block;
10             padding: 2px 3px;
11             margin: 3px 5px;
12             border: 1px solid slategrey;
13         }
14         .condition-div a.active{
15             background-color: lightslategrey;
16         }
17     </style>
18 </head>
19 <body>
20     <h1>过滤条件</h1>
21     <div class="condition-div">
22         <div>
23             {% filter_all arg_dict 'article_type_id' %}
24             {% filter_article_type article_type arg_dict %}
25         </div>
26         <div>
27             {% filter_all arg_dict 'category_id' %}
28             {% filter_category category arg_dict %}
29         </div>
30     </div>
31 
32     <h1>查询结果</h1>
33     <ul>
34         {% for row in result %}
35             <li>{{ row.od }} - {{ row.title }}</li>
36         {% endfor %}
37     </ul>
38 
39 </body>
40 </html>
View Code

这样才看着高端嘛。。。给一个不会Django的看到这个模板,直接疯了,什么鬼。。。我还是回家种田吧。。。

 

 

 

单例模式

单例模式其实算是对于面向对象的基础,类的一次补充。按照之前的思路,每次对于类的方法的调用,都需要实例化,这样就会产生多个实例化对象。

看下面这个示例

 1 class Foo:
 2     instance = None
 3     def __init__(self):
 4         pass
 5 
 6     def process(self):
 7         print(123)
 8 
 9 obj1 = Foo()
10 obj2 = Foo()
11 print(id(obj1), id(obj2))
View Code

输出结果:

1892383886976 1892383887032

对于上面这种情况,根本不需要实例化多个对象来处理,某种意义上是一种浪费。。。所以我们可以简单修改下。

 1 class Foo:
 2     instance = None
 3     def __init__(self):
 4         pass
 5 
 6     @classmethod
 7     def get_instance(cls):
 8         if Foo.instance:
 9             return Foo.instance
10         else:
11             Foo.instance = Foo()
12             return Foo.instance
13 
14     def process(self):
15         print(123)
16 
17 
18 obj1 = Foo.get_instance()
19 obj2 = Foo.get_instance()
20 print(id(obj1), id(obj2))
View Code

结果

2694976409216 2694976409216

这里判断了已经有一个实例化对象,就返回了实例化对象内存地址给后面的实例化过程。

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

 

使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

1 # mysingleton.py
2 class My_Singleton(object):
3     def foo(self):
4         pass
5  
6 my_singleton = My_Singleton()
View Code

将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

from mysingleton import my_singletonmy_singleton.foo()

 

使用__new__

这里还是用最先引入话题的实例来讲解。其实上面的那个类方法算是低级的单例模式,因为我们改变了类的实例化方法了。

 1 class Foo(object):
 2     instance = None
 3     def __init__(self):
 4         self.name = 'dandy'
 5 
 6     def __new__(cls, *args, **kwargs):
 7         if not Foo.instance:
 8             Foo.instance = object.__new__(cls, *args, **kwargs)
 9         return Foo.instance
10 
11     def process(self):
12         print(123)
13 
14 obj1 = Foo()
15 obj2 = Foo()
16 print(obj1, obj2)
View Code
<__main__.Foo object at 0x000001F599138EB8> <__main__.Foo object at 0x000001F599138EB8>

 

 

beautifulsoup4

快速开始

 1 html_doc = """
 2 <html><head><title>The Dormouse's story</title></head>
 3 <body>
 4 <p class="title"><b>The Dormouse's story</b></p>
 5 
 6 <p class="story">Once upon a time there were three little sisters; and their names were
 7 <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
 8 <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
 9 <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
10 and they lived at the bottom of a well.</p>
11 
12 <p class="story">...</p>
13 """
14 
15 from bs4 import BeautifulSoup
16 soup = BeautifulSoup(html_doc)
17 
18 print(soup.prettify())
View Code
# <html>
#  <head>
#   <title>
#    The Dormouse's story
#   </title>
#  </head>
#  <body>
#   <p class="title">
#    <b>
#     The Dormouse's story
#    </b>
#   </p>
#   <p class="story">
#    Once upon a time there were three little sisters; and their names were
#    <a class="sister" href="http://example.com/elsie" id="link1">
#     Elsie
#    </a>
#    ,
#    <a class="sister" href="http://example.com/lacie" id="link2">
#     Lacie
#    </a>
#    and
#    <a class="sister" href="http://example.com/tillie" id="link2">
#     Tillie
#    </a>
#    ; and they lived at the bottom of a well.
#   </p>
#   <p class="story">
#    ...
#   </p>
#  </body>
# </html>

 

几个简单的浏览结构化数据的方法:

soup.title
# <title>The Dormouse's story</title>soup.title.name
# u'title'soup.title.string
# u'The Dormouse's story'soup.title.parent.name
# u'head'soup.p
# <p class="title"><b>The Dormouse's story</b></p>soup.p['class']
# u'title'soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>soup.find_all('a')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]soup.find(id="link3")
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

 

遍历寻找<a>标签的链接:

for link in soup.find_all('a'):print(link.get('href'))# http://example.com/elsie# http://example.com/lacie# http://example.com/tillie

获取文档中所有文字内容:

print(soup.get_text())# The Dormouse's story
#
# The Dormouse's story
#
# Once upon a time there were three little sisters; and their names were
# Elsie,
# Lacie and
# Tillie;
# and they lived at the bottom of a well.
#
# ...

主要解析器,优缺点:

解析器使用方法优势劣势
Python标准库BeautifulSoup(markup, "html.parser")
  • Python的内置标准库
  • 执行速度适中
  • 文档容错能力强
  • Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
lxml HTML 解析器BeautifulSoup(markup, "lxml")
  • 速度快
  • 文档容错能力强
  • 需要安装C语言库
lxml XML 解析器

BeautifulSoup(markup, ["lxml", "xml"])

BeautifulSoup(markup, "xml")

  • 速度快
  • 唯一支持XML的解析器
  • 需要安装C语言库
html5libBeautifulSoup(markup, "html5lib")
  • 最好的容错性
  • 以浏览器的方式解析文档
  • 生成HTML5格式的文档
  • 速度慢
  • 不依赖外部扩展

 

推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.

提示: 如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,查看 解析器之间的区别 了解更多细节

将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄.

from bs4 import BeautifulSoupsoup = BeautifulSoup(open("index.html"))soup = BeautifulSoup("<html>data</html>")

首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码

BeautifulSoup("Sacré bleu!")
<html><head></head><body>Sacré bleu!</body></html>

然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档

 

对象的种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment .

Tag

Tag 对象与XML或HTML原生文档中的tag相同:

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# <class 'bs4.element.Tag'>

Name & Attributes

每个tag都有自己的名字,通过 .name 来获取:
tag.name
# u'b'如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档:
tag.name = "blockquote"
tag
# <blockquote class="boldest">Extremely bold</blockquote>一个tag可能有很多个属性. tag <b class="boldest"> 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:
tag['class']
# u'boldest'也可以直接”点”取属性, 比如: .attrs :
tag.attrs
# {u'class': u'boldest'}tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样
tag['class'] = 'verybold'
tag['id'] = 1
tag
# <blockquote class="verybold" id="1">Extremely bold</blockquote>del tag['class']
del tag['id']
tag
# <blockquote>Extremely bold</blockquote>tag['class']
# KeyError: 'class'
print(tag.get('class'))
# None

 

多值属性

HTML 4定义了一系列可以包含多个值的属性.在HTML5中移除了一些,却增加更多.最常见的多值的属性是 class (一个tag可以有多个CSS的class). 还有一些属性 rel , rev , accept-charset , headers , accesskey . 在Beautiful Soup中多值属性的返回类型是list:

css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]css_soup = BeautifulSoup('<p class="body"></p>')
css_soup.p['class']
# ["body"]

如果某个属性看起来好像有多个值,但在任何版本的HTML定义中都没有被定义为多值属性,那么Beautiful Soup会将这个属性作为字符串返回

id_soup = BeautifulSoup('<p id="my id"></p>')
id_soup.p['id']
# 'my id'

将tag转换成字符串时,多值属性会合并为一个值

rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>')
rel_soup.a['rel']
# ['index']
rel_soup.a['rel'] = ['index', 'contents']
print(rel_soup.p)
# <p>Back to the <a rel="index contents">homepage</a></p>

如果转换的文档是XML格式,那么tag中不包含多值属性

xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
xml_soup.p['class']
# u'body strikeout'

  

遍历字符串

字符串常被包含在tag内.Beautiful Soup用 NavigableString 类来包装tag中的字符串:

tag.string
# u'Extremely bold'
type(tag.string)
# <class 'bs4.element.NavigableString'>

一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在 遍历文档树 和 搜索文档树 中的一些特性. 通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串:

unicode_string = unicode(tag.string)
unicode_string
# u'Extremely bold'
type(unicode_string)
# <type 'unicode'>

tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法:

tag.string.replace_with("No longer bold")
tag
# <blockquote>No longer bold</blockquote>

NavigableString 对象支持 遍历文档树 和 搜索文档树 中定义的大部分属性, 并非全部.尤其是,一个字符串不能包含其它内容(tag能够包含字符串或是其它tag),字符串不支持 .contents 或 .string 属性或 find() 方法.

如果想在Beautiful Soup之外使用 NavigableString 对象,需要调用 unicode() 方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存.

更多请参考:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

 1 result = '''<p>千万人<strong>较</strong>去年我</p>
 2 <p>请问千万人<span style="color: #ff6600;">群若群感通片没人</span>呢 而非狗肉<span style="font-family: 'Microsoft YaHei';">人GV奇</span>偶偶陪<span style="font-family: 仿宋;">你围殴</span>既然v</p>
 3 <p>我打完分配人</p>
 4 <script>alert(123)</script>'''
 5 
 6 from bs4 import BeautifulSoup
 7 soup = BeautifulSoup(result, 'html.parser')
 8 tag = soup.find('script')  # 查询script标签
 9 tag.clear()  # 清除掉标签,2个script:<script></script>
10 tag.hidden = True  # 隐藏标签中的内容
11 
12 span = soup.find('span')  # 找到span标签
13 del span.attrs['style']  # 删除所有属性
14 content = soup.decode()  # 
15 print(content)
16 
17 ########
18 <p>千万人<strong>较</strong>去年我</p>
19 <p>请问千万人<span>群若群感通片没人</span>呢 而非狗肉<span style="font-family: 'Microsoft YaHei';">人GV奇</span>偶偶陪<span style="font-family: 仿宋;">你围殴</span>既然v</p>
20 <p>我打完分配人</p>
View Code

对于标签的白名单

 1 result = '''<p>千万人<strong>较</strong>去年我</p>
 2 <p>请问千万人<span style="color: #ff6600;">群若群感通片没人</span>呢 而非狗肉<span style="font-family: 'Microsoft YaHei';">人GV奇</span>偶偶陪<span style="font-family: 仿宋;">你围殴</span>既然v</p>
 3 <p>我打完分配人</p>
 4 <script>alert(123)</script>'''
 5 
 6 from bs4 import BeautifulSoup
 7 soup = BeautifulSoup(result, 'html.parser')
 8 tags = ['p', 'span']
 9 
10 for tag in soup.find_all():
11     if tag.name in tags:
12         pass
13     else:
14         tag.hidden = True
15         tag.clear()
16 
17 content = soup.decode()
18 print(content)
19 ##################
20 <p>千万人去年我</p>
21 <p>请问千万人<span style="color: #ff6600;">群若群感通片没人</span>呢 而非狗肉<span style="font-family: 'Microsoft YaHei';">人GV奇</span>偶偶陪<span style="font-family: 仿宋;">你围殴</span>既然v</p>
22 <p>我打完分配人</p>
View Code
 1 result = '''<p class='c1' id='p1'>千万人<strong>较</strong>去年我</p>
 2 <p>请问千万人<span id='span11' class='span-class' style="color: #ff6600;">群若群感通片没人</span>呢 而非狗肉<span style="font-family: 'Microsoft YaHei';">人GV奇</span>偶偶陪<span style="font-family: 仿宋;">你围殴</span>既然v</p>
 3 <p>我打完分配人</p>
 4 <script>alert(123)</script>'''
 5 
 6 from bs4 import BeautifulSoup
 7 soup = BeautifulSoup(result, 'html.parser')
 8 tags = {
 9     'p': ['class'],
10     'span': ['id',]
11 }
12 
13 for tag in soup.find_all():
14     if tag.name in tags:
15         pass
16     else:
17         tag.hidden = True
18         tag.clear()
19         continue
20     input_attrs = tag.attrs
21     valid_attrs = tags[tag.name]
22     for key in list(input_attrs.keys()):
23         if key in valid_attrs:
24             pass
25         else:
26             del tag.attrs[key]
27 content = soup.decode()
28 print(content)
View Code

 

转载于:https://www.cnblogs.com/wuzdandz/p/8399418.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/250968.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据恢复软件

链接&#xff1a;https://pan.baidu.com/s/1n6x5vhW-3SY8MAvvnqVtog 密码&#xff1a;thh0转载于:https://www.cnblogs.com/huanu/p/9452039.html

VMware

1.VMware软件安装&#xff1a; https://jingyan.baidu.com/article/9f7e7ec09da5906f281554d6.html 2&#xff0c;镜像文件下载地址&#xff1a;http://www.cnbeta.com/articles/tech/566773.htm 有图形界面。 或是在官网&#xff1a;https://wiki.centos.org/Download 2.cento…

【重要】ES6-23 JavaScript模块化

前端js模块化的演变发展 模块化解决的问题 传统模块化、插件化 CommonJS AMD/CMD ES6模块化 ES6以前 没有js引擎 一开始js写在html的script标签里js内容增多&#xff0c;抽取出index.js文件&#xff0c;外部引入js再增加&#xff0c;index.html对应index.js index2.html对应ind…

jquery --- 多选下拉框的移动(穿梭框)

效果如下: 几个注意地方: 1.多选下拉框需要添加 multiple 2.获取选中的元素KaTeX parse error: Expected EOF, got # at position 3: (#̲id option:selec…(#id option:not(:selected)) 下面是代码的各个部分实现, 方便引用,最后是总体代码,方便理解 添加选中到右边: // …

ES6-24 生成器与迭代器的应用

手写生成器 先done再false&#xff0c;不然index就提前了一步1 var arr [1,2] function generator(arr){var i 0;return{next(){var done i > arr.length ? true : false,value done ? undefined : arr[i];return {value : value,done : done} }} } var gen gener…

jquery --- 收缩兄弟元素

点击高亮的收缩兄弟元素. 思路: 1.点击的其实是tr.(类为parent) 2.toggleClass可以切换样式 3.slblings(’.class’).toggle 可以根据其类来进行隐藏显示 代码如下: <!DOCTYPE html> <html> <head> <meta charset"utf-8"><style>.pa…

Webpack基础

path.resolve // 只要以/开头&#xff0c;就变为绝对路径 // ./和直接写效果相同 var path require("path") //引入node的path模块path.resolve(/foo/bar, ./baz) // returns /foo/bar/baz path.resolve(/foo/bar, baz) // returns /foo/bar/baz path.res…

LeetCode:二叉树相关应用

LeetCode&#xff1a;二叉树相关应用 基础知识 617.归并两个二叉树 题目 Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge them into a new …

jquery --- 网页选项卡

点击,不同的tab_menu,显示不同的tab_box 注意点: 1.获取ul下,当前li的编号. $(‘div ul li’).index(this) 2.显示ul下编号为$index的li -> $(‘ul li’).eq($index) <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <style&g…

Webpack进阶(二)代码分割 Code Splitting

源代码index.js里包含2部分① 业务逻辑代码 1mb② 引入&#xff08;如lodash包&#xff09;的代码 1mb若更新了业务逻辑代码&#xff0c;但在浏览器运行时每次都下载2mb的index.js显然不合理&#xff0c;第三方包是不会变的 手动拆分 webpack.base.js entry: {main: path.re…

5177. 【NOIP2017提高组模拟6.28】TRAVEL (Standard IO)

Description Input Output Solution 有大佬说&#xff1a;可以用LCT做。&#xff08;会吗&#xff1f;不会&#xff09; 对于蒟蒻的我&#xff0c;只好用水法&#xff08;3s&#xff0c;不虚&#xff09;。 首先选出的泡泡怪一定是连续的一段 L&#xff0c; R 然后 L 一定属于虫…

python 3.x 爬虫基础---http headers详解

python 3.x 爬虫基础 python 3.x 爬虫基础---http headers详解 python 3.x 爬虫基础---Urllib详解 python 3.x 爬虫基础---Requersts,BeautifulSoup4&#xff08;bs4&#xff09; python 3.x 爬虫基础---正则表达式 前言  上一篇文章 python 爬虫入门案例----爬取某站上海租房…

Webpack进阶(三)

懒加载 lazy loading 用到的时候才加载vue 首屏不加载index.js const oBtn document.getElementById(j-button) oBtn.onclick async function () {const div await createElement()document.body.appendChild(div) } async function createElement() {const { default: _ …

P2634 [国家集训队]聪聪可可

链接&#xff1a;https://www.luogu.org/problemnew/show/P2634 题目描述 聪聪和可可是兄弟俩&#xff0c;他们俩经常为了一些琐事打起来&#xff0c;例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑&#xff08;可是他们家只有一台电脑&#xff09;……遇到这种问…

算法 --- 快慢指针判断链表是否有环

解题思路: 分别设置2个指针(s,q)指向链表的头部,s每次指向下面一个(s s.next),q每次指向下面2个(q q.next.next). 如果存在环,q总会在某一时刻追上s /*** Definition for singly-linked list.* function ListNode(val) {* this.val val;* this.next null;* }*//**…

node --- 使用nrm改变npm的源

说明: 1.nrm只是单纯的提供了几个常用的下载包的URL地址,方便我们再使用npm装包是 很方便的进行切换. 2.nrm提供的cnpm 和通过 cnpm装包是2个不同的东西(使用cnpm install必须先安装cnpm -> npm install -g cnpm) 安装nrm: // linux $ [sudo] npm install --global nrm// w…

MySQL教程(三)—— MySQL的安装与配置

1 安装MySQL 打开附件中的文件&#xff08;分别对应电脑系统为32/64位&#xff09;。点next。 三个选项&#xff0c;分别对应典型安装、自定义安装和完全安装&#xff0c;在此选择典型安装&#xff08;初学者&#xff09;。 点install。 广告&#xff0c;忽略它。 安装完成…

c++ --- 字符串中的标点符号

题外话: 最近看node,发现node中好多强大的功能都设计到C,为了加深对node的理解,开始简单的学习一下C语法 ispunct: 统计string对象中标点符号的个数 #include <iostream> using namespace std; int main () {string s ("Hello World!");decltype(s.size()) p…

Hadoop(5)-Hive

在Hadoop的存储处理方面提供了两种不同的机制&#xff0c;一种是之前介绍过的Hbase&#xff0c;另外一种就是Hive&#xff0c;有关于Hbase&#xff0c;它是一种nosql数据库的一种&#xff0c;是一种数据库&#xff0c;基于分布式的列式存储&#xff0c;适合海量数据的操作&…

认识及实现MVC

gitee M&#xff1a;Model 数据模型&#xff08;模型层&#xff09;→ 操作数据库&#xff08;对数据进行增删改查&#xff09; V&#xff1a;View视图层 → 显示视图或视图模板 C&#xff1a;Controller 控制器层 → 逻辑层 数据和视图关联挂载和基本的逻辑操作 API层 前端请…