首页 > 代码库 > 报障系统之博客主页及后台管理

报障系统之博客主页及后台管理

个人博客:

url函数(路由系统):

"""baozhang URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r^$, views.home, name=home)
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r^$, Home.as_view(), name=home)
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r^blog/, include(blog.urls))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^all/(?P<type_id>\d+)/, views.index),
    url(r^login/, views.login),
    url(r^logout/, views.logout),
    url(r^check_code/, views.check_code),

    url(r^register/, views.register),注册页面

    url(r^(?P<site>\w+)/(?P<key>((tag)|(category)|(date)))/(?P<val>\w+-*\w*).html$, views.home_filter),#筛选
    url(r^(?P<site>\w+).html$, views.home),#个人已开通博客主页
    url(r^(?P<site>\w+)/p/(?P<nid>\w+).html$, views.detail),  # 文章详细
    url(r^(?P<site>\w+)/(?P<nid>\d+).html$, views.article),#评论
    url(r^up.html$, views.up),#点赞或踩
    url(r^lizhi-(?P<article_type_id>\d+)-(?P<categpry_id>\d+)-(?P<tags_id>\d+).html$, views.lizhi),
    url(r^upload/, views.upload),#上传

    # url(r^openblog/, views.openblog),
    # url(r^(\w+)/, views.blog),
    url(r^test/, views.test),
    # url(r^(\w+)/$, views.home),
    url(r^, views.index),#个人主页
]

报障系统主页

技术分享
def index(request, *args, **kwargs):
    """
    个人主页
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    # print(request.path_info)  # /all/1/  /all/2/
    username = request.session.get(username)
    obj = models.UserInfo.objects.filter(username=username).values(blog__site).first()


    condition = {}
    type_id = int(kwargs.get(type_id)) if kwargs.get(type_id) else None  # 如果kwargs.get(type_id)有值时转成整型没有值等于None
    if type_id:
        condition[article_type_id] = type_id

    article_list = models.Article.objects.filter(**condition)
    # article_type_id = models.IntegerField(choices=type_choices, default=None)
    type_choice_list = models.Article.type_choices  # 文章分类
    user_list = models.UserInfo.objects.filter()
    return render(
        request,
        index.html,
        {
            username: username,
            obj: obj,
            type_id: type_id,
            type_choice_list: type_choice_list,
            article_list: article_list,
        }
    )
个人主页函数

Class Form类

注册类:

技术分享
from django.forms import Form
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from app01 import models

class RegisterForm(Form):
    username = fields.CharField(
        required=True,
        widget=widgets.TextInput(
            attrs={class:form-control,placeholder:用户名为6-10个字符}
        ),
        min_length=6,
        max_length=10,
        strip=True,
        error_messages={
            required: 用户名不能为空,
            min_length:用户名至少为6个字符,
            max_length:用户名不超过10个字符,
        },
    )
    password = fields.CharField(
        required=True,
        widget=widgets.PasswordInput(
            attrs={class:form-control,placeholder:密码为8-12个字符}
        ),
        min_length=8,
        max_length=12,
        strip=True,
        validators=[
            RegexValidator(r((?=.*\d))^.{8,12}$,必须包含数字),
            RegexValidator(r((?=.*[a-zA-Z]))^.{8,12},必须包含字母),
            # RegexValidator(r((?=.*[^a-zA-Z0-9]))^.{8,12},必须包含特殊字符),
            # RegexValidator(r^.(\s){8,12},必须包含空格),
        ],#用于对密码的正则验证
        error_messages={
            required: 密码不能为空,
            min_length:密码不能少于8个字符,
            max_length:密码最多为12个字符!,
        }
    )
    password_again = fields.CharField(
        required=True,
        widget=widgets.PasswordInput(
            attrs={class:form-control,placeholder:密码为8-12个字符}
        ),
        min_length=8,
        max_length=12,
        strip=True,
        error_messages={required:请再次输入密码!,}
    )
    nickname = fields.CharField(
        required=True,
        widget=widgets.TextInput(
            attrs={class:form-control,placeholder:请输入昵称}
        )
    )
    email = fields.EmailField(
        required=True,
        widget=widgets.TextInput(attrs={class:form-control,placeholder:请输入邮箱}),
        # strip=True,
        # error_messages={required:邮箱不能为空,invalid:请输入正确的邮箱格式},
    )
    avatar = fields.FileField(widget=widgets.FileInput(attrs={id:imgFile,class:f1}))
    code = fields.CharField(widget=widgets.TextInput(attrs={class:form-control,placeholder:请输入验证码}))
    def clean_username(self):
        #对于username扩展验证,查看是否存在
        username = self.cleaned_data[username]
        users = models.UserInfo.objects.filter(username=username).count()
        if users:#如果用户名已存在
            raise ValidationError(用户名已经存在!)
        return username
    def clean_email(self):
        #对于email的扩展验证,查看是否存在
        email = self.cleaned_data[email]
        email_count = models.UserInfo.objects.filter(email=email).count()
        if email_count:
            raise ValidationError(邮箱已经存在!)
        return email
    # def _clean_password(self):#验证两次输入密码是否一致
    #     password1 = self.cleaned_data[password]
    #     password2 = self.cleaned_data[password_again]
    #     if password1 and password2:
    #         if password1 != password2:
    #             raise ValidationError(您两次输入的密码不一致)

    def __init__(self,request,*args,**kwargs):#构造方法,传request参数
        super(RegisterForm,self).__init__(*args,**kwargs)#完成原有form功能以外
        self.request = request#再封装一个request

    def clean_code(self):
        input_code = self.cleaned_data[code]
        session_code = self.request.session.get(code)#session取验证码
        if input_code.upper() == session_code.upper():#验证相等时
            return input_code#
        raise ValidationError(验证码错误)

    def clean(self):  # 验证两次输入密码是否一致
        p1 = self.cleaned_data.get(password)
        p2 = self.cleaned_data.get(password_again)
        if p1 == p2:
            # return self.cleaned_data
            return None
        # else:
        #     raise ValidationError(密码不一致)
        self.add_error("password_again",ValidationError(密码不一致))

            # except ValidationError as e:
            # self.add_error(name, e)
    # def clean(self):
    #     #基于form对象的验证,字段全部验证通过会调用clean函数验证
    #     self._clean_password()#调用函数
    #     p1 = self.cleaned_data[password]
    #     p2 = self.cleaned_data[password_again]
    #     return p2

    # def clean_password(self):
    #     p1 = self.cleaned_data[password]
    #     p2 = self.cleaned_data[password_again]
        return p2
RegisterForm类(加一个构造方法)

登录类:

技术分享
class LoginForm(forms.Form):
    """用户登录form验证"""
    username = fields.CharField(
        required=True,
        widget=widgets.TextInput(attrs={class: form-control, placeholder: 请输入用户名}),
        min_length=6,
        max_length=10,
        strip=True,
        error_messages={required: 用户名不能为空, }
    )
    password = fields.CharField(
        required=True,
        widget=widgets.TextInput(attrs={class: form-control, placeholder: 请输入密码}),
        max_length=12,
        min_length=8,
        strip=True,
        error_messages={required: 密码不能为空, }
    )

    def clean(self):
        username = self.cleaned_data.get(username)
        password = self.cleaned_data.get(password)
        user_list = models.UserInfo.objects.filter(username=username).first()
        if username and password:
            if not user_list:
                raise ValidationError(用户名不存在,请重新输入)
            elif password != user_list.password:
                raise ValidationError(密码错误)
LoginForm类

用户登录视图函数

技术分享
# 用户登录
def login(request):  # GET请求
    """
    用户登录
    :param request:
    :return:
    """
    if request.method == "GET":
        obj = LoginForm()
        return render(request, login.html, {obj: obj})
    else:
        # print(request.POST)

        # obj = LoginForm(request.POST)

        # errors = {}
        # print(obj.errors)
        # print(obj)
        # print(request.session)
        # if obj.is_valid():
        input_code = request.POST.get(code)
        # print(input_code)
        session_code = request.session.get(code)
        if input_code.upper() == session_code.upper():  # 判断验证码是否正确
            username = request.POST.get(username)
            user_list = models.UserInfo.objects.filter(username=username).first()
            print(user_list)
            if user_list:
                password = request.POST.get(password)
                if user_list.password == password:
                    request.session[is_login] = true
                    request.session[username] = user_list.username
                    return redirect(/)
                else:
                    msg = 密码错误
                    obj = LoginForm(request.POST)
                    return render(request, login.html, {msg: msg, obj: obj})
            else:
                msg = 该账号不存在
                obj = LoginForm(request.POST)
                return render(request, login.html, {msg: msg, obj: obj})
        else:
            msg = 验证码错误
            obj = LoginForm(request.POST)
            return render(request, login.html, {msg: msg, obj: obj})
            #         if request.POST.get(auto_login):
            #             request.session.get_expiry(60*60*24*24)
            #         # request.session[is_login] = true
            #         # request.session[username] = data.get(username)
            #         print(request.session[username])
            #         print(123)
            #         return redirect(/)
            #     else:
            #         errors[code] = 请输入正确的验证码
            #         return render(request,login.html,{obj:obj,errors:errors})
            # return render(request,login.html,{obj:obj})
login 用户登录

退出登录:

技术分享
def logout(request):
    """
    用户退出登录
    :param request:
    :return:
    """
    try:
        # 删除is_login对应的value值
        del request.session[is_login]
        del request.session[username]
    except KeyError:
        pass
    return redirect(/login/)
#验证码
logout(删除session里的值)

获取验证码:

技术分享
#验证码
def check_code(request):
    """
    #读取硬盘中的文件,在页面显示
    # f = open(static/images/aa.png,rb)
    # data = f.read()
    # f.close()
    # return HttpResponse(data)
    #先写到本地,再读出到页面
    # from PIL import Image
    # f = open(code.png,wb)
    # img = Image.new(mode=RGB,size=(120,30),color=(255,255,255))
    # img.save(f,png)
    # f.close()
    #
    # f = open(code.png,rb)
    # data = f.read()
    # f.close()
    #内存开辟一块空间
    from PIL import Image,ImageDraw,ImageFont
    from io import BytesIO
    f = BytesIO()
    img = Image.new(mode=RGB,size=(120,30),color=(255,255,255))#图片对象
    draw = ImageDraw.Draw(img,mode=RGB)#画笔对象
    #画点
    draw.point([10,10],fill="red")
    draw.point([30,10],fill="red")
    #画线
    draw.line((15,10,50,50),fill=red)
    draw.line((45,20,100,100),fill=(0,255,0))
    #画圆圈
    draw.arc((0,0,30,30),0,360,fill="red")
    #写文本内容
    # draw.text([0,0],python,"red")

    # font = ImageFont.truetype("kumo.ttf",28)
    # draw.text([0,0],python,(0,255,0),font=font)
    import random #生成随机数
    # char_list = []
    # for i in range(5):
    #     char = chr(random.randint(65,90))
    #     char_list.append(char)
    # ‘‘.join(char_list)
    # v = ‘‘.join([chr(random.randint(65,90)) for i in range(5)])
    char_list = []
    for i in range(5):
        char = chr(random.randint(65,90))
        char_list.append(char)#保存写的随机字符
        font = ImageFont.truetype("kumo.ttf",28)
        draw.text([i*24,0],char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
    # code = ‘‘.join(char_list)
    img.save(f,png)
    data = f.getvalue()#读取内存里的值

    code = ‘‘.join(char_list)
    print(request.session)#<django.contrib.sessions.backends.db.SessionStore object at 0x00000258DB88DC88>
    request.session[code] = code#保存在session里
    """
    from io import BytesIO
    from utils.random_check_code import rd_check_code
    stream = BytesIO()
    img, code = rd_check_code()
    img.save(stream, png)
    # data = stream.getvalue()
    request.session[code] = code
    return HttpResponse(stream.getvalue())
check_code获取验证码

用户注册时上传头像:

技术分享
import os
#用户上传图片
def upload(request):
    print(request.POST, request.FILES)
    file_obj = request.FILES.get(imgUrl)  #取文件时,需以FILES获取文件数据
    file_path = os.path.join(static/img/, file_obj.name)
    print(file_path)
    with open(file_path, wb) as f:  # 以wb方式写入到指定目录(bytes格式写入) # 写字节方式打开空文件,拼接文件路径
        for trunk in file_obj.chunks():  # 写入到指定目录
            f.write(trunk)
    return HttpResponse("/" + file_path)
upload用户上传头像

用户注册:

技术分享
def register(request):
    """
    用户注册
    :param request:
    :return:
    """
    if request.method == "GET":
        obj = RegisterForm(request)
        return render(request, register.html, {obj: obj})
    else:
        # 验证码
        obj = RegisterForm(request, request.POST, request.FILES)
        if obj.is_valid():
            print(type(obj.cleaned_data))
            dict = {}
            dict[username] = obj.cleaned_data[username]
            dict[password] = obj.cleaned_data[password]
            dict[nickname] = obj.cleaned_data[nickname]
            dict[email] = obj.cleaned_data[email]
            dict[avatar] = obj.cleaned_data[avatar]
            models.UserInfo.objects.create(**dict)
            return redirect(/)
        else:
            # print(obj.errors[__all__])
            # print(obj.errors[NON_FIELD_ERRORS])
            """
            <ul class="errorlist nonfield"><li>密码不一致</li></ul>
            <ul class="errorlist nonfield"><li>密码不一致</li></ul>
           """
            # obj.errors是一个字典
            # - 对于Form组件错误信息
            """
            {
                __all__: [错误1,错误2]
            user: [错误1,错误2]
            password: [错误1,错误2]
            }
            """

        return render(request, register.html, {obj: obj})
用户注册函数(form验证)

个人博客主页:

技术分享
def home(request,site):
    """
    #个人博客主页
    :param request:
    :param site:
    :return:
    """
    # condition= {}
    # type_id = int(kwargs.get(type_id)) if kwargs.get(type_id) else None
    # if type_id:
    #     condition[article_type_id] = type_id
    # type_choice_list = models.Article.type_choices
    blog = models.Blog.objects.filter(site=site).first()  # 创建一个博客对象

    if not blog:
        return redirect(/)
    # print(site)

    #按照:标签,分类,时间
    # 标签
    tag_list = models.Article2Tag.objects.filter(article__blog=blog).values(tag_id, tag__title).annotate(ct=Count(id))
    #分类
    category_list = models.Article.objects.filter(blog=blog).values(category_id,category__title).annotate(ct=Count(nid))#queryset[字典1,字典2......]

    #时间
    date_list = models.Article.objects.filter(blog=blog).extra(select={ctime:"date_format(create_time,‘%%Y-%%m‘)"}).values(ctime).order_by(-ctime).annotate(ct=Count(nid))
    #文章分页
    all_count = models.Article.objects.all().count()
    page_info = PageInfo(request.GET.get(page), all_count, 2, /bingabcd.html, 11)

    article_list = models.Article.objects.all()[page_info.start():page_info.end()]

    # #获取时间分组
    #
    # date_list = models.Article.objects.filter(blog=blog).extra(select={c:"date_format(create_time,‘%%Y-%%m‘)"}).values(c).order_by(-c).annotate(ct=Count(nid))
    """
    nid,title
    """
    return render(
        request,
        home.html,
        {
            site:site,#博客后缀
            blog: blog,#博客对象
            article_list:article_list,#文章列表
            page_info:page_info,#分页

            tag_list:tag_list,#标签
            category_list:category_list,#分类
            date_list:date_list,#时间
        }
    )
        # 1.当前博客的所有文章
home个人博客主页

个人博客文章筛选:

技术分享
#个人博客筛选
def home_filter(request,site,key,val):
    """
    个人博客筛选
    :param request:
    :param site:
    :param key:
    :param val:
    :return:
    """
    # blog = models.Blog.objects.filter(site=site).select_related(user).first()#related_name直接连表,如果做for循环query_set对象时,减少查询次数
    # print(blog)
    # if not blog:
    #     return redirect(/)

    blog = models.Blog.objects.filter(site=site).first()  # 创建一个博客对象
    print(blog)
    if not blog:
        return redirect(/)
    #按照:标签,分类,时间
    #标签
    tag_list = models.Article2Tag.objects.filter(article__blog=blog).values(tag_id,tag__title).annotate(ct=Count(id))
    print(tag_list)
    print(tag_list.query)
    #分类
    category_list = models.Article.objects.filter(blog=blog).values(category_id,category__title).annotate(ct=Count(nid))#queryset[字典1,字典2......]
    print(category_list)
    print(category_list.query)
    #时间
    date_list = models.Article.objects.filter(blog=blog).extra(select={ctime:"date_format(create_time,‘%%Y-%%m‘)"}).values(ctime).order_by(-ctime).annotate(ct=Count(nid))
    print(date_list.query)
    print(1111)
    #文章分页
    all_count = models.Article.objects.all().count()#总页数
    page_info = PageInfo(request.GET.get(page), all_count, 2, /bingabcd.html, 11)
    if key == tag:
        article_list = models.Article.objects.filter(tags__nid=val,blog=blog)[page_info.start():page_info.end()] #文章列表
        print(article_list)
        # v = models.Article.objects.filter(blog=blog,article2tag__tag__title=val)
        # print(v.query)
        # #自定义第三张表
        # #自己反向关联
        # v = models.Article.objects.filter(blog=blog,article2tag__tag=val)
        # #通过M2M字段
        # v = models.Article.objects.filter(blog=blog,tags__nid=val)
    elif key == category:
        article_list = models.Article.objects.filter(category_id=val,blog=blog)[page_info.start():page_info.end()] #文章列表
        print(article_list)
    else:
        # article_list = models.Article.objects.filter(create_time=val,blog=blog).all()[page_info.start():page_info.end()]#文章列表
        article_list = models.Article.objects.filter(blog=blog).extra(where=["date_format(create_time,‘%%Y-%%m‘)=%s"],params=[val,])[page_info.start():page_info.end()]
        print(article_list)


    return render(
        request,
        home_filter.html,
        {
            blog:blog,
            tag_list:tag_list,
            category_list:category_list,
            date_list:date_list,
            article_list:article_list,
            page_info:page_info
        }
    )
home_filter个人博客筛选

查看文章详细页:

技术分享
#查看文章详细页
def detail(request,*args,**kwargs):#文章详细
    """
    查看文章详细页
    :param request:
    :return:
    """
    site = kwargs.get("site")
    nid = kwargs.get(nid)
    url = request.path_info
    user_id = request.session.get(user_id)
    # 博客信息
    blog = models.Blog.objects.filter(site=site).first()
    if user_id:
        userinfo = models.UserInfo.objects.filter(nid=user_id).first()
    else:
        userinfo = False
    #文章
    obj = models.Article.objects.filter(blog__site=site,nid=nid).first()
    print(obj)
    #分类列表
    category_list = models.Article.objects.filter(blog__site=site).values(category__title,category_id).annotate(c=Count(nid))
    #标签列表
    tag_list = models.Article.objects.filter(blog__site=site).values(tags__title,tags__nid).annotate(c=Count(nid))
    #时间列表
    date_list = models.Article.objects.filter(blog=blog).extra(select={c:"date_format(create_time,‘%%Y-%%m‘)"}).values(c).order_by(-c).annotate(ct=Count(nid))

    comment_list = []
    com = []
    comment = enumerate(obj.comment_set.all())
    for i,j in comment:
        com = []
        com.append(i+1)
        com.append(j)
        comment_list.append(com)
    return render(
        request,
        article_detail.html,
        {
            url:url,
            obj:obj,
            blog:blog,
            date_list:date_list,
            category_list: category_list,
            tag_list: tag_list,
            userinfo:userinfo,
            comment:comment_list,
        }
    )
detail查看文章详细页

 文章中赞或者踩:

待补充:

 

 

博客系统后台管理:

后台管理:

组合筛选:

技术分享
#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",{
            width: "700px",
            height: "300px",
            uploadJson: /upload_img.html,
            extraFileUploadParams: {
                "csrfmiddlewaretoken":"{{ csrf_token }}"  
            {# 需要添加CSRF验证#}
            }
        })
    </script>
</body>
</html>

KindEditor上传图片
KindEditor上传图片

补充:

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

BeautifulSoup模块基本使用:

技术分享
beautifulsoup4的基本使用
安装:
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/img\lang.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的基本使用
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",{
            width: "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攻击

 

补充:

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

参考博客:http://www.cnblogs.com/wupeiqi/articles/6283017.html

 

报障系统之博客主页及后台管理