bingabcd

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

个人博客:

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

 

分类:

技术点:

相关文章: