报障系统之基础建设

通过Django admin填充基本数据:

#admin.py
from django.contrib import admin
from app01 import models

admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.ArticleDetail)
admin.site.register(models.Blog)
admin.site.register(models.Category)
admin.site.register(models.Comment)
admin.site.register(models.Tag)
admin.site.register(models.UpDown)
admin.site.register(models.UserFans)
admin.site.register(models.UserInfo)


#创建用户:
python manage.py createsuperuser


#访问:
127.0.0.1:8000/admin/


#models.py

from django.db import models


class UserInfo(models.Model):
    """
    用户表
    """
    nid = models.BigAutoField(primary_key=True)
    username = models.CharField(verbose_name='用户名', max_length=32, unique=True)
    password = models.CharField(verbose_name='密码', max_length=64)
    nickname = models.CharField(verbose_name='昵称', max_length=32)
    email = models.EmailField(verbose_name='邮箱', unique=True)
    avatar = models.ImageField(verbose_name='头像',upload_to='static/images')

    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    fans = models.ManyToManyField(verbose_name='粉丝们',
                                  to='UserInfo',
                                  through='UserFans',
                                  related_name='f',
                                  through_fields=('user', 'follower'))

    def __str__(self):
        return self.nickname
class Blog(models.Model):
    """
    博客信息
    """
    nid = models.BigAutoField(primary_key=True)
    title = models.CharField(verbose_name='个人博客标题', max_length=64)
    site = models.CharField(verbose_name='个人博客后缀', max_length=32, unique=True)
    theme = models.CharField(verbose_name='博客主题', max_length=32)
    user = models.OneToOneField(to='UserInfo', to_field='nid')

    def __str__(self):
        return self.title


class UserFans(models.Model):
    """
    互粉关系表
    """
    user = models.ForeignKey(verbose_name='博主', to='UserInfo', to_field='nid', related_name='users')
    follower = models.ForeignKey(verbose_name='粉丝', to='UserInfo', to_field='nid', related_name='followers')

    class Meta:
        unique_together = [
            ('user', 'follower'),
        ]


class Category(models.Model):
    """
    博主个人文章分类表
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='分类标题', max_length=32)

    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')

    def __str__(self):
        return "%s-%s" %(self.blog.title,self.title)

class ArticleDetail(models.Model):
    """
    文章详细表
    """
    content = models.TextField(verbose_name='文章内容', )

    article = models.OneToOneField(verbose_name='所属文章', to='Article', to_field='nid')


class UpDown(models.Model):
    """
    文章顶或踩
    """
    article = models.ForeignKey(verbose_name='文章', to='Article', to_field='nid')
    user = models.ForeignKey(verbose_name='赞或踩用户', to='UserInfo', to_field='nid')
    up = models.BooleanField(verbose_name='是否赞')

    class Meta:
        unique_together = [
            ('article', 'user'),
        ]


class Comment(models.Model):
    """
    评论表
    """
    nid = models.BigAutoField(primary_key=True)
    content = models.CharField(verbose_name='评论内容', max_length=255)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    reply = models.ForeignKey(verbose_name='回复评论', to='self', related_name='back', null=True)
    article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid')
    user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid')


class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='标签名称', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')

    def __str__(self):
        return "%s-%s" %(self.blog.title,self.title)



class Article(models.Model):
    nid = models.BigAutoField(primary_key=True)
    title = models.CharField(verbose_name='文章标题', max_length=128)
    summary = models.CharField(verbose_name='文章简介', max_length=255)
    read_count = models.IntegerField(default=0)
    comment_count = models.IntegerField(default=0)
    up_count = models.IntegerField(default=0)
    down_count = models.IntegerField(default=0)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)

    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')
    category = models.ForeignKey(verbose_name='文章类型', to='Category', to_field='nid', null=True)

    type_choices = [
        (1, "Python"),
        (2, "Linux"),
        (3, "OpenStack"),
        (4, "GoLang"),
    ]
    # 网站分类

    article_type_id = models.IntegerField(choices=type_choices, default=None)

    tags = models.ManyToManyField(
        to="Tag",
        through='Article2Tag',
        through_fields=('article', 'tag'),
    )

    def __str__(self):
        return "%s-%s" %(self.blog.title,self.title)

class Article2Tag(models.Model):
    article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid')
    tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid')

    class Meta:
        unique_together = [
            ('article', 'tag'),
        ]
报障系统之填充基本数据

 报障系统之个人博客主页:

#urls.py
    url(r'^(w+)/$', views.home),
    
#views.py
def home(request,site):
    """
    访问个人博客主页 http://127.0.0.1:8000/fangshaowei/
    :param request:  请求相关信息
    :param site: 个人博客后缀,如: www.xxx.com/xxxxx/
    :return:
    """

    blog = models.Blog.objects.filter(site=site).first()
    if not blog:
        return redirect('/')

    # 按照:分类,标签,时间
    # 分类
    category_list = models.Article.objects.filter(blog=blog).values('category_id','category__title').annotate(ct=Count('nid'))

    # 标签
    tag_list = models.Article2Tag.objects.filter(article__blog=blog).values('tag_id','tag__title').annotate(ct=Count('id'))

    # 时间
    date_list = models.Article.objects.filter(blog=blog).extra(select={'ctime':"strftime('%%Y-%%m',create_time)"}).values('ctime').annotate(ct=Count('nid'))
    # select xxx as x

    article_list = models.Article.objects.all()

    return render(
        request,
        'home.html',
        {
            'blog':blog,
            'category_list':category_list,
            'tag_list':tag_list,
            'date_list':date_list,
            'article_list':article_list,
        }
    )

#home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="/static/css/theme/{{ blog.theme }}.css" />
</head>
<body>
    <div class="c1">
        <div class="c11">{{ blog.user.nickname }}</div>
        <div class="c12">{{ blog.title }}</div>
    </div>
    <div class="c2">
        <h3>分类</h3>
        <ul>
            {% for item in category_list %}
                <li>
                    <a href="/{{ blog.site }}/category/{{ item.category_id }}/">{{ item.category__title }}({{ item.ct }})</a>
                </li>
            {% endfor %}
        </ul>
    </div>
    <div class="c3">
        <h3>标签</h3>
        <ul>
            {% for item in tag_list %}
                <li>
                    <a href="/{{ blog.site }}/tag/{{ item.tag_id }}/">{{ item.tag__title }}({{ item.ct }})</a>
                </li>
            {% endfor %}
        </ul>
    </div>
    <div>
        <h3>时间</h3>
        <ul>
            {% for item in date_list %}
                <li>
                    <a href="/{{ blog.site }}/date/{{ item.ctime }}/">{{ item.ctime }}({{ item.ct }})</a>
                </li>
            {% endfor %}
        </ul>
    </div>

    <div class="c4">
        {% for row in article_list %}
            <div>
                <a href="/{{ blog.site }}/{{ row.nid }}.html">{{ row.title }}</a>
                <div>{{ row.summary }}</div>
            </div>
        {% endfor %}
    </div>
</body>
</html>
个人博客主页代码

后台管理

组合筛选:

#URL
#urls.py

# url(r'^screen-(?P<article_type_id>d+)-(?P<category_id>d+)-(?P<article2tag__tag_id>d+).html$', views.screen),
url(r'^screen-(?P<article_type_id>d+)-(?P<category_id>d+)-(?P<tags__nid>d+).html$', views.screen),

#视图函数
#views.py

def screen(request,**kwargs):
    # print(kwargs)
    condition = {}
    for k,v in kwargs.items():
        kwargs[k] = int(v)
        if v != '0':
            condition[k] = v
    print(condition)

    #大分类
    type_list = models.Article.type_choices

    #个人分类
    catagory_list = models.Category.objects.filter(blog_id=1)

    #个人标签
    tag_list = models.Tag.objects.filter(blog_id=1)

    #进行筛选
    condition['blog_id']=1
    article_list = models.Article.objects.filter(**condition)

    return render(request,'screen.html',{
        'type_list':type_list,
        'catagory_list':catagory_list,
        'tag_list':tag_list,
        'article_list':article_list,
        'kwargs':kwargs,
    })
    

#模板语言
#screen.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .condition a{
            display: inline-block;
            padding: 5px;
        }
        .condition a.active{
            background-color: #0a386a;
            color: white;
        }
    </style>
</head>
<body>

    <h3>筛选</h3>
    <div class="condition">
        大大分类:
        {% if kwargs.article_type_id == 0 %}
            <a class="active" href="/screen-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a>
        {% else %}
            <a href="/screen-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a>
        {% endif %}
        {% for row in type_list %}
            {% if row.0 == kwargs.article_type_id %}
                <a class="active" href="/screen-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a>
            {% else %}
                <a href="/screen-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a>
            {% endif %}
        {% endfor %}
    </div>
    <div class="condition">
        个人分类:
        <a href="#">全部</a>
        {% for row in catagory_list %}
            <a href="{{ row.nid }}">{{ row.title }}</a>
        {% endfor %}
    </div>
    <div class="condition">
        个人标签:
        <a href="#">全部</a>
        {% for row in tag_list %}
            <a href="{{ row.nid }}">{{ row.title }}</a>
        {% endfor %}
    </div>
    <h3>结果</h3>
    {% for row in article_list %}
        <div>
            <h4><a href="#">{{ row.title }}</a></h4>
            <div>{{ row.summary }}</div>
        </div>
    {% endfor %}
</body>
</html>
报障系统后台管理组合筛选

KindEditor上传图片:

参考文档:KindEditor

#URL路由
#urls.py
url(r'^upload_img.html$', views.upload_img),

#视图函数
#views.py
def upload_img(request):
    import os
    # print(request.POST, request.FILES)
    # upload_type = request.GET.get('dir')
    # 根据上传得文件类型控制上传得文件目录

    file_obj = request.FILES.get('imgFile')
    file_path = os.path.join('static/img',file_obj.name)
    with open(file_path,'wb') as f:
        for chunk in file_obj.chunks():
            f.write(chunk)

    dic = {
        'error':0,
        'url':'/'+file_path,
        'message':'错误了...'
    }
    import json
    return HttpResponse(json.dumps(dic))


#模板语言
#editor.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form method="POST" action="/editor.html" novalidate>
    {#如果不加novalidate,{{ obj.content }}会报错#}
        <p>
            文章标题
            {{ obj.title }}
        </p>
        {% csrf_token %}
        <div>
            <div>文章内容</div>
            <div>
                {{ obj.content }}
            </div>
        </div>
        <input type="submit" value="提交">
    </form>

    <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script>
    <script>
        KindEditor.create("#i1",{
             "700px",
            height: "300px",
            uploadJson: '/upload_img.html',
            extraFileUploadParams: {
                "csrfmiddlewaretoken":"{{ csrf_token }}"  
            {# 需要添加CSRF验证#}
            }
        })
    </script>
</body>
</html>
KindEditor上传图片

补充:

文件上传其实内部就是iframe+form 伪Ajax操作
input type='file' name='imgFile' 提交
可以通过filePostName 更改默认name属性:
filePostName: 'fafafa'

BeautifulSoup模块基本使用:

安装:
pip3 install beautifulsoup4
导入模块:
from bs4 import BeautifulSoup

valid_tag = [] #只能设置标签名的白名单
valid_tag = {} #既能加标签名又能加标签的属性的白名单

tag.name 获取标签名

soup.find() #查找第一个标签
soup.find_all() #查找所有的p标签

tag.clear() #清除标签中的内容
tag.decompose() #清空标签中的内容并且删除标签

decode() soup对象转换成字符串
encode() soup对象转换成字节



#示例:

content = """
<p id='i1' a='123' b='999'>
    <script>alert(123)</script>
</p>
<p id='i2'>
    <div>
        <p>asfjldjf</p>
    </div>
    <img id='i3' src="/static/imglang.jpg" alt="" />
</p>
"""

from bs4 import BeautifulSoup
soup = BeautifulSoup(content,'html.parser')


#设置名叫valid_tag的白名单:

# valid_tag = ['p','img','div']  #只能放置标签名,列表形式

valid_tag = {                    #既能加标签名又能加标签的属性,字典形式。
    'p':['class','id'],
    'img':['src'],
    'div':['class']
}


# v=soup.find(name='p',attrs={'id':'i2'}) #查找第一个p标签,并且id是i2
# print(v)

# tag = soup.find(name='p') #查找第一个p标签,生成的是对象的形式,可以通过“.”形式继续查找
# sc=tag.find('script') 
# print(sc)

# v=soup.find_all(name='p') #查找所有的p标签
# print(v)

# tags = soup.find_all() #查找所有的标签
# for tag in tags:   #tag.name是标签名
#     if tag.name not in valid_tag: #如果标签名不在白名单中则情况标签中的内容
#         tag.clear()

tags = soup.find_all()
for tag in tags:
    if tag.name not in valid_tag:
        tag.decompose() #删除不再白名单中的标签
    if tag.attrs:
        for k in list(tag.attrs.keys()): #{id:'i1',a=123,b=999}
            if k not in valid_tag[tag.name]:
                del tag.attrs[k]

content_str=soup.decode()  #去掉特殊标签后,拿到它的字符串
print(content_str) #打印过滤后的标签字符串
beautifulsoup4的基本使用

基于KindEditor和BeautifuSoup实现防止XSS攻击:

基于KindEditor和BeautifuSoup实现防止XSS攻击

#URL路由系统
#urls.py
url(r'^editor.html$', views.editor),
#可视化编辑器

url(r'^see.html$', views.see),
#查看可视化编辑器生成的样式

url(r'^upload_img.html$', views.upload_img),
#上传图片


#视图函数
#views.py

CONTENT = ""
from app01.forms import ArticleForm
def editor(request):
    if request.method=="GET":
        obj = ArticleForm()
        return render(request,'editor.html',{'obj':obj})
    else:
        obj = ArticleForm(request.POST)
        if obj.is_valid():
            content = obj.cleaned_data['content']
            global CONTENT
            CONTENT = content
            print(content)
            return HttpResponse("...")

def see(request):
    return render(request,'see.html',{'con':CONTENT})

def upload_img(request):
    import os
    # print(request.POST, request.FILES)
    # upload_type = request.GET.get('dir')
    # 根据上传得文件类型控制上传得文件目录

    file_obj = request.FILES.get('imgFile')
    file_path = os.path.join('static/img',file_obj.name)
    with open(file_path,'wb') as f:
        for chunk in file_obj.chunks():
            f.write(chunk)

    dic = {
        'error':0,
        'url':'/'+file_path,
        'message':'错误了...'
    }
    import json
    return HttpResponse(json.dumps(dic))

    
#模板语言
#editor.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form method="POST" action="/editor.html" novalidate>
{#        如果不加novalidate,{{ obj.content }}会报错#}
        <p>
            文章标题
{#            <input type="text" name="title">#}
            {{ obj.title }}
        </p>
{#        <p>#}
{#            选择分类#}
{#            <select name="" id="">#}
{##}
{#            </select>#}
{#        </p>#}
{#        <p>#}
{#            选择标签#}
{#            <input type="checkbox">#}
{#            <input type="checkbox">#}
{#            <input type="checkbox">#}
{#            <input type="checkbox">#}
{#        </p>#}
        {% csrf_token %}
        <div>
            <div>文章内容</div>
            <div>
{#                <textarea name="content" id="i1" cols="30" rows="10"></textarea>#}
                {{ obj.content }}
            </div>
        </div>
        <input type="submit" value="提交">
    </form>

    <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script>
    <script>
        KindEditor.create("#i1",{
             "700px",
            height: "300px",
{#            items: [ 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',],#}
{#            noDisableItems: ['undo','redo'],#}
{#            designMode: false,#}
{#            resizeType:1,#}
            uploadJson: '/upload_img.html',
            extraFileUploadParams: {
                "csrfmiddlewaretoken":"{{ csrf_token }}"
            {# 需要添加CSRF验证#}
            }
        })
    </script>
</body>
</html>


#Form组件
#forms.py
from django.forms import Form
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError

class ArticleForm(Form):
    title = fields.CharField(max_length=64)
    content  = fields.CharField(
        widget=widgets.Textarea(attrs={'id':'i1'})
    )

    def clean_content(self):
        from bs4 import BeautifulSoup

        valid_tag = {
            'p': ['class', 'id'],
            'img': ['src'],
            'div': ['class']
        }

        old=self.cleaned_data['content']
        soup = BeautifulSoup(old, 'html.parser')

        tags = soup.find_all()
        for tag in tags:
            if tag.name not in valid_tag:
                tag.decompose()  # 删除不再白名单中的标签
            if tag.attrs:
                for k in list(tag.attrs.keys()):  # {id:'i1',a=123,b=999}
                    if k not in valid_tag[tag.name]:
                        del tag.attrs[k]

        content_str = soup.decode()
        return content_str
防止XSS攻击

补充:

防止XSS攻击为什么不用黑名单,要用白名单?
使用白名单过滤html标签比黑名单操作起来更简单,把攻击锁定在自己可控制范围内。

参考文档:http://www.cnblogs.com/wupeiqi/articles/6283017.html

 总结:报障系统

量化内网运维人员工作量
	1. 分角色
	2. 三类用户:
			普通用户
			运维人员
			总监
	3. 知识库(必须会)
	
	4. 权限(公共组件) *****
原文地址:https://www.cnblogs.com/luchuangao/p/7202460.html