zoukankan      html  css  js  c++  java
  • 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" onclick="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;  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                  '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;  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                  '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_singleton
     
    my_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语言库
    html5lib BeautifulSoup(markup, "html5lib")
    • 最好的容错性
    • 以浏览器的方式解析文档
    • 生成HTML5格式的文档
    • 速度慢
    • 不依赖外部扩展

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

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

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

    from bs4 import BeautifulSoup
    
    soup = 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
  • 相关阅读:
    Poj2104-K-th Number(主席树)
    Poj3237-Tree(树链剖分)
    Spoj QTREE(树链剖分)
    字符串算法
    网络流算法
    利用DiDiSoft OpenPGP Library for .NET 程序加密解密文件
    利用GPG4Win加密解密文件
    .NET Standard和.NET Framework的区别【转】
    Aras学习笔记 (6) Aras Client Side代码弹出标准ItemType内容窗口
    WebClient使用DownloadFile下载文件超时的解决办法
  • 原文地址:https://www.cnblogs.com/wuzdandz/p/8399418.html
Copyright © 2011-2022 走看看