博客系统作业

博客系统

1 搞清楚需求(产品经理) 

  1,基于用户认证组件和Ajax实现登录验证(图片验证码)
  2,基于forms组件和Ajax实现注册功能
  3,设计系统首页(文章列表渲染)
  4,设计个人站点页面
  5,文章详情页
  6,实现文章点赞功能
  7,实现文章评论功能
    ---文章的评论
    ---评论的评论
  8,富文本编辑框和防止xss攻击

2 设计表结构



from django.contrib.auth.models import User,AbstractUser
 
  class UserInfo(AbstractUser):
    """用户信息"""
    nid=models.AutoField(primary_key=True)
    telephone=models.CharField(max_length=11,null=True,unique=True)
    avatar=models.FileField(upload_to='avatars/',default="/avatars/default.png")
    create_time=models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
    blog=models.OneToOneField(to='blog',to_field='nid',null=True)
    def __str__(self):
        return self.username
        
  class Blog(models.Model):
    """博客信息表(站点表)"""
    nid=models.AutoField(primary_key=True)
    title=models.CharField(verbose_name='个人博客标题',max_length=64)
    site_name=models.CharField(verbose_name='站点名称',max_length=64)
    theme=models.CharField(verbose_name='博客主题',max_length=32)
    
    def __str__(self):
        return self.title

  class Category(models.Model):
    """博主个人文章分类表"""
    nid=models.AutoField(primary_key=True)
    title=models.CharField(verbose_name='分类标题',max_length=32)
    blog=models.ForeignKey(verbose_name='所属博客',to='Blog',to_field='nid')
    
    def __str__(self):
        return self.title

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

  class Article(models.Model):
    nid=models.AutoField(primary_key=True)
    title=models.CharField(verbose_name='文章标题',max_length=50)
    desc=models.CharField(verbose_name='文章描述',max_length=255)
    create_time=models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
    content=models.TextField()
    
    comment_count=models.IntegerField(default=0)
    up_count=models.IntegerField(default=0)
    down_count=models.IntegerField(default=0)
    
    user=models.ForeignKey(verbose_name='作者',to='UserInfo',to_field='nid')
    category=models.ForeignKey(to="Category",to_field='nid',null=True)
    tags=models.ManyToManyField(
        to='Tag',
        through='Article2Tag',
        through_fields=('article','tag'),
    )

    def __str__(self):
        return self.title        

  class Article2Tag(models.Model):
    nid=models.AutoField(primary_key=True)
    article=models.ForeignKey(verbose_name='文章',to='Article',to_field='nid')
    tag=models.ForeignKey(verbose_name='标签',to='Tag',to_field='nid')
    
    class Meta:
        unique_together=[
            ('article','tag'),
        ]
    def __str__(self):
        v=self.article.title + '---' + self.tag.title
        return v        

  class ArticleUpDown(models.Model):
    """点赞表"""
    nid=models.AutoField(primary_key=True)
    user=models.ForeignKey('UserInfo',null=True)
    article=models.ForeignKey('Article',null=True)
    is_up=models.BooleanField(default=True)
    
    class Meta:
        unique_together=[
            ('article','user'),
        ]

  class Comment(models.Model):
    """评论表"""
    nid=models.AutoField(primary_key=True)
    article=models.ForeignKey(verbose_name='评论文章',to='Article',to_field='nid')
    user=models.ForeignKey(verbose_name='评论者',to='UserInfo',to_field='nid')
    content=models.CharField(verbose_name='评论内容',max_length=255)
    create_time=models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
    parent_comment=models.ForeignKey('self',null=True)
    
    def __str__(self):
        return self.content
View Code       

3 按着每一个功能进行开发

 验证码

示例代码:

# #!/usr/bin/python3
# # -*- coding: utf-8 -*-
# # @Time    : 2018/8/30 9:51
# # @File    : validCode.py
#

import random
import sys, os


def get_random_color():
    return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)


def get_valid_code_img(request):
    # 方式1:
    # pa_base = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
    # pa_img = os.path.join(pa_base, r'mediaavatarslufei.jpg')
    # with open(pa_img, "rb") as f:
    #     data = f.read()

    # 方式2:  # pip install pillow

    # from PIL import Image
    #
    # img = Image.new("RGB", (270, 40), color=get_random_color())
    #
    # with open("validCode.png", "wb") as f:
    #     img.save(f, "png")
    #
    # with open("validCode.png", "rb") as f:
    #     data = f.read()

    # 方式3:

    # from PIL import Image
    # from io import BytesIO
    #
    # img = Image.new("RGB", (270, 40), color=get_random_color())
    # f = BytesIO()
    # img.save(f, "png")
    # data = f.getvalue()
    # 方式4:

    from PIL import Image, ImageDraw, ImageFont
    from io import BytesIO
    import random

    img = Image.new("RGB", (270, 40), color=get_random_color())

    draw = ImageDraw.Draw(img)
    kumo_font = ImageFont.truetype("static/font/kumo.ttf", size=32)

    valid_code_str = ""
    for i in range(5):
        random_num = str(random.randint(0, 9))
        random_low_alpha = chr(random.randint(95, 122))
        random_upper_alpha = chr(random.randint(65, 90))
        random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])
        draw.text((i * 50 + 20, 5), random_char, get_random_color(), font=kumo_font)

        # 保存验证码字符串
        valid_code_str += random_char

    width = 270
    height = 40
    for i in range(10):
        x1 = random.randint(0, width)
        x2 = random.randint(0, width)
        y1 = random.randint(0, height)
        y2 = random.randint(0, height)
        draw.line((x1, y1, x2, y2), fill=get_random_color())

    for i in range(100):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())

    print("valid_code_str", valid_code_str)

    # request.session["valid_code_str"] = valid_code_str

    '''
    1 sdajsdq33asdasd
    2 COOKIE {"sessionid":sdajsdq33asdasd}
    3 django-session
      session-key       session-data
      sdajsdq33asdasd   {"valid_code_str":"12345"}


    '''

    f = BytesIO()
    img.save(f, "png")
    data = f.getvalue()

    return data
View Code

view中调用:

def get_valid_code_img(request):
    """
    基于PIL模块动态生成响应状态码图片
    :param request:
    :return:
    """
    img_data = validCode.get_valid_code_img(request)

    return HttpResponse(img_data)
View Code

登录页面login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">

</head>
<body>
<h3>登录页面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">

            <form>
                {% csrf_token %}
                <div class="form-group">
                    <label for="user">用户名</label>
                    <input type="text" id="user" class="form-control">
                </div>
                <div class="form-group">
                    <label for="pwd">密码</label>
                    <input type="password" id="pwd" class="form-control">
                </div>


                <div class="form-group">
                    <label for="pwd">验证码</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" id="valid_code">
                        </div>
                        <div class="col-md-6">
                            <img width="270" height="36" id="valid_code_img" src="/my_demo2/get_valid_code_img/" alt="">
                        </div>
                    </div>
                </div>


                <input type="button" class="btn btn-default login_btn" value="submit"><span class="error"></span>
                <a href="/register/" class="btn btn-success pull-right">注册</a>
            </form>

        </div>
    </div>
</div>


<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>

    // 刷新验证码
    $("#valid_code_img").click(function () {

        $(this)[0].src += "?"

    });

    // 登录验证
    $(".login_btn").click(function () {


        $.ajax({
            url: "/my_demo2/get_valid_code_img/",
            type: "post",
            data: {
                user: $("#user").val(),
                pwd: $("#pwd").val(),
                valid_code: $("#valid_code").val(),
                csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
            },
            success: function (data) {
                console.log(data);

                if (data.user) {
                    if (location.search) {
                        location.href = location.search.slice(6)
                    }
                    else {
                        location.href = "/index/"
                    }

                }
                else {
                    $(".error").text(data.msg).css({"color": "red", "margin-left": "10px"});
                    setTimeout(function () {
                        $(".error").text("");
                    }, 1000)

                }
            }
        })

    })

</script>
</body>
</html>
View Code

 admin使用

1,在app应用下的admin.py中添加相关models中的所有类

from django.contrib import admin

# Register your models here.
from blog import models

admin.site.register(models.UserInfo)
admin.site.register(models.Tag)
admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.ArticleUpDown)
admin.site.register(models.Category)
admin.site.register(models.Comment)
admin.site.register(models.Blog)
View Code

2,google中打开网址:http://127.0.0.1:8000/admin,根据逻辑添加相关数据

 media组件

settings.py

# 与用户上传相关的配置
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"

urls.py

# media配置:
    re_path(r"media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT}),

 注册功能头像示例代码

# 头像文件获取
            avator_obj = request.FILES.get("avator")
            extra = {}
            if avator_obj:
                extra["avatar"] = avator_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)

 日期处理

mysql中

date_format

============date,time,datetime===========

create table t_mul_new(d date,t time,dt datetime);

insert into t_mul_new values(now(),now(),now());

select * from t_mul;


mysql> select * from t_mul;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2017-08-01 | 19:42:22 | 2017-08-01 19:42:22 |
+------------+----------+---------------------+
1 row in set (0.00 sec)


select date_format(dt,"%Y/%m/%d") from t_mul;
View Code

extra介绍

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句

extra可以指定一个或多个 参数,例如 select, where or tables. 这些参数都不是必须的,但是你至少要使用一个!要注意这些额外的方式对不同的数据库引擎可能存在移植性问题.(因为你在显式的书写SQL语句),除非万不得已,尽量避免这样做

extra 参数之select

The select 参数可以让你在 SELECT 从句中添加其他字段信息,它应该是一个字典,存放着属性名到 SQL 从句的映射。
queryResult=models.Article.objects.extra(select={'is_recent': "create_time > '2017-09-05'"})
结果集中每个 Entry 对象都有一个额外的属性is_recent, 它是一个布尔值,表示 Article对象的create_time 是否晚于2017-09-05.

练习:
# 查询当前站点每一个年月的名称以及对应的文章数
in sqlite:

    article_obj=models.Article.objects.extra(select={"standard_time":"strftime('%%Y-%%m-%%d',create_time)"}).values("standard_time","nid","title")
    print(article_obj)
    # <QuerySet [{'title': 'MongoDb 入门教程', 'standard_time': '2017-09-03', 'nid': 1}]>

in mysql
    # ret=models.Article.objects.extra(select={"is_recent":"create_time > '2018-09-05'"}).values("title","is_recent")
    # print(ret)

    # 方式1:
    # date_list=models.Article.objects.filter(user=user).extra(select={"y_m_date":"date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date","c")
    # print(date_list)


    # 方式2:

    # from django.db.models.functions import TruncMonth
    #
    # ret=models.Article.objects.filter(user=user).annotate(month=TruncMonth("create_time")).values("month").annotate(c=Count("nid")).values_list("month","c")
    # print("ret----->",ret)
View Code

 TruncMonth日期归档查询的方式

from django.db.models.functions import TruncMonth

Sales.objects
    .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
    .values('month')                          # Group By month
    .annotate(c=Count('id'))                  # Select the count of the grouping
    .values('month', 'c')                     # (might be redundant, haven't tested) select month and count 
View Code

 base页面(函数)

基础页面中

<div class="col-md-9">
	{% block content %}
	
	{% endblock %}
</div>

 业务页面

{% extends 'base.html' %}
{% block content %}
相关html代码

{% endblock %}

 view函数(三个列表参数都需要传cate_list、date_list、tag_list)

def get_classification_data(username):
    user = UserInfo.objects.filter(username=username).first()
    blog = user.blog

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")

    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")

    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")

    return {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list}


def article_detail(request, username, article_id):
    """
    文章详情页
    :param request:
    :param username:
    :param article_id:
    :return:
    """
    context = get_classification_data(username)
    return render(request, "article_detail.html", context)
View Code
def home_site(request, username, **kwargs):
    """
    个人站点
    :param request:
    :param username:
    :return:
    """
    user = UserInfo.objects.filter(username=username).first()
    # 判断用户是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查询当前站点对象

    blog = user.blog
    article_list = models.Article.objects.filter(user=user)

    if kwargs:
        condition = kwargs.get("condition")
        param = kwargs.get("param")  # 2012-12

        if condition == "category":
            article_list = article_list.filter(category__title=param)
        elif condition == "tag":
            article_list = article_list.filter(tags__title=param)
        else:
            year, month = param.split("/")
            article_list = article_list.filter(create_time__year=year, create_time__month=month)
    print(article_list)
    print(article_list.query)
    # # 1 当前用户或者当前站点对应所有文章
    # ret = models.Article.objects.filter(user=user).all()
    # print(ret)
    # # 每一个后的表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
    # # 查询每一个分类名称以及对应的文章数
    # ret_cate = models.Category.objects.values("pk").annotate(c=Count("article")).values("title", "c")
    # print(ret_cate)
    #
    # # 查询当前站点的每一个分类名称以及对应的文章数
    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")
    # print(cate_list)
    #
    # # 查询当前站点的每一个标签名称以及对应的文章数
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")
    # print(tag_list)
    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")
    # print(date_list)

    return render(request, "home_site.html",
                  {"username": username, "blog": blog, "article_list": article_list, "tag_list": tag_list,
                   "cate_list": cate_list, "date_list": date_list, })
View Code

 base页面(标签)

blog应用下新建templatetags文件夹(py)

my_tag.py

from django import template
from django.db.models import Count
from blog import models

register = template.Library()


@register.simple_tag
def multi_tag(x, y):
    return x * y


@register.inclusion_tag("classification.html")
def get_classification_style(username):
    user = models.UserInfo.objects.filter(username=username).first()
    blog = user.blog

    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")).values_list(
        "title", "c")

    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")).values_list("title", "c")

    date_list = models.Article.objects.filter(user=user).extra(
        select={"y_m_date": "date_format(create_time,'%%Y/%%m')"}).values("y_m_date").annotate(
        c=Count("nid")).values_list("y_m_date", "c")

    return {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list}
View Code

简单调用tag

{% load my_tags %}
{% multi_tag 3 9 %}
{% load my_tags %}
{% get_classification_style username %}

 视图函数

def home_site(request, username, **kwargs):
    """
    个人站点
    :param request:
    :param username:
    :return:
    """
    user = UserInfo.objects.filter(username=username).first()
    # 判断用户是否存在!
    if not user:
        return render(request, "not_found.html")

    # 查询当前站点对象

    blog = user.blog
    article_list = models.Article.objects.filter(user=user)

    if kwargs:
        condition = kwargs.get("condition")
        param = kwargs.get("param")  # 2012-12

        if condition == "category":
            article_list = article_list.filter(category__title=param)
        elif condition == "tag":
            article_list = article_list.filter(tags__title=param)
        else:
            year, month = param.split("/")
            article_list = article_list.filter(create_time__year=year, create_time__month=month)

    return render(request, "home_site.html",
                  {"username": username, "blog": blog, "article_list": article_list})


def article_detail(request, username, article_id):
    """
    文章详情页
    :param request:
    :param username:
    :param article_id:
    :return:
    """
    user = UserInfo.objects.filter(username=username).first()
    blog = user.blog
    return render(request, "article_detail.html", locals())
View Code

 classification.html

 <div>
    <div class="panel panel-warning">
                <div class="panel-heading">我的标签</div>
                <div class="panel-body">
                    {% for tag in tag_list %}
                        <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                    {% endfor %}

                </div>
            </div>

    <div class="panel panel-danger">
        <div class="panel-heading">随笔分类</div>
        <div class="panel-body">
            {% for cate in cate_list %}
                <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
            {% endfor %}
        </div>
    </div>

    <div class="panel panel-success">
        <div class="panel-heading">随笔归档</div>
        <div class="panel-body">
            {% for date in date_list %}
                <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
            {% endfor %}
        </div>
    </div>
 </div>
View Code

 评论es6显示

页面反引号,视图传参

html代码
success: function (data) {
    var create_time = data.create_time;
    var username = data.username;
    var content = data.content;

    var s = `<li class="list-group-item">
        <div>
            <span>${create_time}</span>&nbsp;&nbsp;
            <a href=""><span>${username}</span></a>
        </div>
        <div class="comment_con">
            <p>${content}</p>
        </div>

    </li>`;
    $("ul.comment_list").append(s);
}
view代码:
def comment(request):
    article_id = request.POST.get("article_id")
    pid = request.POST.get("pid")
    content = request.POST.get("content")
    user_id = request.user.pk
    comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,
                                                parent_comment_id=pid)

    response = {"create_time": comment_obj.create_time.strftime("%Y-%m-%d %X"), "username": request.user.username,
                "content": content, }
    
    return JsonResponse(response)
View Code

 回复按钮

点击回复,焦点进入文本框立马失去焦点:a标签中属性href要去掉

html代码
<a class="pull-right reply_btn" username="{{ comment.user.username }}">回复</a>
js代码
// 回复
$(".reply_btn").click(function () {
    $("#comment_content").focus();
    var val = "@" + $(this).attr("username") + "
";
    $('#comment_content').val(val);
});
View Code

 评论数

视图返回[{},{}],页面遍历拼装渲染数据

视图:
def get_comment_tree(request):
    article_id = request.GET.get("article_id")
    response = list(models.Comment.objects.filter(article_id=article_id).order_by("pk").values("pk", "content",
                                                                                               "parent_comment_id"))

    return JsonResponse(response, safe=False)
页面
<p class="tree_btn">评论树</p>
<div class="comment_tree">

</div>
<script>
    $(".tree_btn").click(function () {
        $.ajax({
            url: "/get_comment_tree/",
            type: "get",
            data: {
                article_id: "{{ article_obj.pk }}"
            },
            success: function (comment_list) {
                console.log(comment_list);

                $.each(comment_list, function (index, comment_object) {
                    var pk = comment_object.pk;
                    var content = comment_object.content;
                    var parent_comment_id = comment_object.parent_comment_id;
                    var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span></div>';

                    if (!parent_comment_id) {
                        $(".comment_tree").append(s);
                    } else {
                        $("[comment_id=" + parent_comment_id + "]").append(s);
                    }
                });
            }
        })
    });
</script>    
样式:
.comment_item {
    margin-left: 20px;
}
View Code

 事务

from django.db import transaction
# 事务操作
with transaction.atomic():
	comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,
												parent_comment_id=pid)
	models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)

发送邮件

单独启动线程发送比较效率高

视图代码:

article_obj = models.Article.objects.filter(pk=article_id).first()
# 发送邮件

from django.core.mail import send_mail
from cnblog import settings

# send_mail(
#     "您的文章%s新增了一条评论内容"%article_obj.title,
#     content,
#     settings.EMAIL_HOST_USER,
#     ["916852314@qq.com"]
# )

# 效率高,时间短
import threading

t = threading.Thread(target=send_mail, args=("您的文章%s新增了一条评论内容" % article_obj.title,
                                             content,
                                             settings.EMAIL_HOST_USER,
                                             ["916852314@qq.com"])
                     )
t.start()

setting代码:

EMAIL_HOST = 'smtp.exmail.qq.com'  # 如果是 163 改成 smtp.163.com
EMAIL_PORT = 465        # 如果是 163 改成 25
EMAIL_HOST_USER = ''           # 帐号
EMAIL_HOST_PASSWORD = ''  # 密码
# DEFAULT_FROM_EMAIL = EMAIL_HOST_USER  # 这个打开后view中 settings.EMAIL_HOST_USER可以不加
EMAIL_USE_SSL = True
View Code

 safe使用

文章内容直接存F12样式中的代码,显示加|safe

<div class="cont">
        {{ article_obj.content|safe }}
    </div>

kindeditor编辑器

添加文章

首页:kindeditor.net/doc.php
上传路径:uploadJson:"/upload/",
是否可拉伸:resizeType:0,
csrf阻止:extraFileUploadParams:{
            csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
        },
指定传入视图的键:filePostName:"upload_img"

setting.py代码:

# 文本编辑器上传图片url
path('upload/', views.upload),

views.py代码:

def upload(request):
    """
    编辑器上传文件接受视图函数
    :param request:
    :return:
    """

    print(request.FILES)
    img_obj=request.FILES.get("upload_img") # 文件对象
    print(img_obj.name)

    path=os.path.join(settings.MEDIA_ROOT,"add_article_img",img_obj.name) # 指定文件上传的路径

    with open(path,"wb") as f:

        for line in img_obj:
            f.write(line)
    # 把上传的图像返回给编辑器
    response = {
        "error":0,
        "url":"/media/add_article_img/%s"%img_obj.name #编辑器可以识别的路径,直接浏览器可以访问的路径
    }
    import json # 编辑器需要json数据
    return HttpResponse(json.dumps(response))

    return HttpResponse("ok")
View Code

摘要样式乱:

desc = content[0:150] # 如果文章是标签html,可以把标签截取断,样式乱
desc=soup.text[0:150]+"..."	

 bs4防止xss攻击

xss提交html代码要使用html模式,不是文本模式

from bs4 import BeautifulSoup
soup=BeautifulSoup(content,"html.parser") # html.parser解析器会把所有html标签解析掉
desc=soup.text[0:150]+"..."  # 去标签之后的文本

视图代码:
def add_article(request):
    """
    后台管理的添加书籍视图函数
    :param request:
    :return:
    """
    if request.method == "POST":
        title = request.POST.get("title")
        content = request.POST.get("content")
        # 防止xss攻击,过滤script标签
        soup = BeautifulSoup(content, "html.parser")
        for tag in soup.find_all():

            print(tag.name)
            if tag.name == "script":
                tag.decompose()
        # 构建摘要数据,获取标签字符串的文本前150个符号

        desc = soup.text[0:150] + "..."

        models.Article.objects.create(title=title, desc=desc, content=content, user=request.user)
        return redirect("/cn_backend/")

    return render(request, "backend/add_article.html")


简单示例:
from bs4 import BeautifulSoup

s = "<h1>hello</h1><span>123</span><script>alert(123)</script>"

soup = BeautifulSoup(s, "html.parser")

# print(soup.text)

print(soup.find_all())  # [<h1>hello</h1>, <span>123</span>, <script>alert(123)</script>]

for tag in soup.find_all():

    print(tag.name)
    if tag.name == "script":
        tag.decompose()  # 删除掉script标签以及内容

print(str(soup))  # <h1>hello</h1><span>123</span>
View Code

pycharm无法安装新模块

pycharm无法安装新模块
报错:
AttributeError: module 'pip' has no attribute 'main'
解决:

找到安装目录下 helpers/packaging_tool.py文件,找到如下代码:
def do_install(pkgs):
    try:
        import pip
    except ImportError:
        error_no_pip()
    return pip.main(['install'] + pkgs)


def do_uninstall(pkgs):
    try:
        import pip
    except ImportError:
        error_no_pip()
    return pip.main(['uninstall', '-y'] + pkgs)
    
修改为:

def do_install(pkgs):
    try:
        #import pip
        try:
            from pip._internal import main
        except Exception:
            from pip import main
    except ImportError:
        error_no_pip()
    return main(['install'] + pkgs)


def do_uninstall(pkgs):
    try:
        #import pip
        try:
            from pip._internal import main
        except Exception:
            from pip import main
    except ImportError:
        error_no_pip()
    return main(['uninstall', '-y'] + pkgs)        
View Code

4 功能测试


5 项目部署上线

原文地址:https://www.cnblogs.com/fmgao-technology/p/9546130.html