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

个人博客:

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查看文章详细页

 文章中赞或者踩:

待补充:

 

 

博客系统后台管理:

后台管理:

组合筛选:

第一种方式:用for循环:

views.py

def lizhi(request,**kwargs):
    print(kwargs)#{'article_type_id': '1', 'category_id': '1', 'tags_id': '0'}#从url传过来的数据
    condition = {}
    for k,v in kwargs.items():
        kwargs[k] = int(v)
        if v != '0':
            condition[k] = v
    print(condition)#{'article_type_id': '1', 'category_id': '1'}
    # 大分类
    type_list = models.Article.type_choices
    print(type_list)#[(1, 'Python'), (2, 'Linux'), (3, 'OpenStack'), (4, 'GoLang'), (5, 'Car')]
    #个人分类
    category_list = models.Category.objects.filter(blog_id=1)#
    print(category_list)#<QuerySet [<Category: bingabcd-Python>, <Category: bingabcd-设计模式>, <Category: bingabcd-机器人>]>
    #个人标签
    tag_list = models.Tag.objects.filter(blog_id=1)
    print(tag_list)#<QuerySet [<Tag: bingabcd-Python之路>, <Tag: bingabcd-Django>, <Tag: bingabcd-HTML>, <Tag: bingabcd-机器人>, <Tag: bingabcd-人工智能>]>
    # 对文章进行筛选
    condition['blog_id']=1
    article_list = models.Article.objects.filter(**condition)
    print(article_list)#<QuerySet [<Article: bingabcd-Python>, <Article: bingabcd-机器人>, <Article: bingabcd-Python基本数据类型>, <Article: bingabcd-Django基础>]>
    return render(request,
                  'lizhi.html',
                  {
                      'type_list':type_list,
                      'category_list':category_list,
                      'tag_list':tag_list,
                      'article_list':article_list,
                      'kwargs':kwargs
                  }
            )
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .condition a{
            display: inline-block;
            padding: 5px;
        }
        .condition a.active{
            background-color: #204d74;
            color: white;
        }
    </style>
</head>
<body>
    <h3>筛选</h3>
    <div class="condition">
        大大分类:
        {% if kwargs.article_type_id == 0 %}
            <a class="active" href="/lizhi-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a>
        {% else %}
            <a href="/lizhi-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="/lizhi-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a>
            {% else %}
                <a href="/lizhi-{{ row.0 }}-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">{{ row.1 }}</a>
            {% endif %}
        {% endfor %}
        <div>
            个人分类
            <a href="#">全部</a>
            {% for row in category_list %}
                <a href="{{ row.nid }}">{{ row.title }}</a>
            {% endfor %}
        </div>

        <div>
            个人标签
            <a href="#">全部</a>
            {% for row in tag_list %}
                <a href="{{ row.nid }}">{{ row.title }}</a>
            {% endfor %}
        </div>

        <div>
            <h3>结果</h3>
            {% for row in article_list %}
                <h4><a href="#">{{ row.title }}</a></h4>
                <div>{{ row.summary }}</div>
            {% endfor %}
        </div>
{#        大大分类:#}
{#        {% if kwargs.article_type_id == 0 %}#}
{#            <a class="active" href="/lizhi-0-{{ kwargs.category_id }}-{{ kwargs.tags__nid }}.html">全部</a>#}
{#        {% else %}#}
{#            <a href="/lizhi-0-{{ kwargs.category_id }}"></a>#}
{#        {% endif %}#}
        
    </div>
</body>
</html>
组合搜索.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>

报障系统后台管理组合筛选
报障系统后台管理组合筛选

第二种方式:用simple_tag+filter

 

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

 

posted on 2017-07-20 01:16  bigdata_devops  阅读(468)  评论(0编辑  收藏  举报

导航