2. 博客项目(二)

博客项目(二)

版权声明:本博客来自路飞学城Python全栈开发培训课件,仅用于学习之用,严禁用于商业用途。
欢迎访问路飞学城官网:https://www.luffycity.com/

本节实现文章的后台管理,包括文章、文章分类、文章标签的增删改查功能。

1. 补充知识点-富文本框的使用

KindEditor 是一套开源的在线HTML编辑器,主要用于让用户在网站上获得所见即所得编辑效果,开发人员可以用 KindEditor 把传统的多行文本输入框(textarea)替换为可视化的富文本输入框。 KindEditor 使用 JavaScript 编写,可以无缝地与 Java、.NET、PHP、ASP 等程序集成,比较适合在 CMS、商城、论坛、博客、Wiki、电子邮件等互联网应用上使用。

为了能够更好地在后台编辑文章,我们会在项目中引入富文本编辑器中的其中一款kindeditor。

html页面:

<script src="/static/js/jquery-3.2.1.min.js"></script>
<script charset="utf-8" src="/static/blog/kindeditor/kindeditor-all.js"></script>

<script>
    KindEditor.ready(function(K) {
            window.editor = K.create('#article_content',{
                width:"800",
                height:"600",
                resizeType:0,
                uploadJson:"/upload/",
                extraFileUploadParams:{
                    csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
                },
                filePostName:"upload_img"


            });
    });
</script>

url路由配置:

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

图像上传的视图函数:

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)
    return HttpResponse("ok")

2. 文章、分类、标签增删改查

创建From模型

# MyForms.py
class ArticleForm(forms.Form):
    title = forms.CharField(max_length=32,
                            min_length=4,
                            label="标题",
                            error_messages={"min_length": "标题太短了,至少4个字符",
                                            "required": "该字段不能为空!"},
                            widget=forms.widgets.TextInput(attrs={'class': 'form-control'}
                                                           ))
    content = forms.CharField(min_length=4,
                              required=False,
                              label="内容(Kindeditor编辑器,不支持拖放/粘贴上传图片)",
                              error_messages={"min_length": "你太短了"},
                              widget=forms.widgets.Textarea(attrs={'class': 'form-control'}
                                                            ))
    category = forms.ChoiceField(label="文章分类", error_messages={"required": "该字段不能为空"},
                                 widget=forms.widgets.Select(attrs={'class': 'form-control'}))
    tags = forms.MultipleChoiceField(label="标签", error_messages={"required": "该字段不能为空"},
                                     widget=forms.widgets.SelectMultiple(attrs={'class': 'form-control'}))

    def __init__(self, *args, **kwargs):
        user = kwargs.pop("user")
        blog = user.blog
        super(ArticleForm, self).__init__(*args, **kwargs)
        self.fields['category'].choices = models.Category.objects.filter(blog=blog).values_list('pk', 'title')
        self.fields['tags'].choices = models.Tag.objects.filter(blog=blog).values_list('pk', 'title')

小技巧:

因为不同用户都有各自的文章分类和标签,所以在初始化文章表单的时候需要根据用户来筛选对应的的记录。此时通过视图函数传输一个user对象,实现对分类和标签的筛选。

配置路由

urlpatterns = [
    ...
    # 后台管理url
    re_path("cn_backend/$",views.cn_backend),
    re_path("cn_backend/add_article/$",views.add_article),
    re_path("^cn_backend/edit_article/(?P<article_id>\d+)$",views.edit_article),
    re_path("^cn_backend/del_article/(?P<article_id>\d+)$",views.del_article),

    re_path("cn_backend/category/$",views.category),
    re_path("cn_backend/del_category/(?P<category_id>\d+)$",views.del_category),

    re_path("cn_backend/tags/$",views.tags),
    re_path("^cn_backend/edit_tag/$",views.edit_tag),
    re_path("cn_backend/del_tag/(?P<tag_id>\d+)$",views.del_tag),

    # 后台上传图片
    path("upload/", views.upload),    
    ...

创建视图函数

# views.py
...
def page_util(request, obj_list, num_of_page=3):
    """
    分页函数,单独处理分页逻辑
    :param request: 页面请求对象
    :param obj_list: 要分页的数据源
    :param num_of_page: 每页要显示的条数
    :return:
    """
    paginator = Paginator(obj_list, num_of_page)
    page = request.GET.get('page', 1)
    currentPage = int(page)

    if paginator.num_pages > 7:
        #  如果大于7,分情况处理
        if currentPage - 3 < 1:
            pageRange = range(1, 8)
        elif currentPage + 3 > paginator.num_pages:
            pageRange = range(currentPage - 6, paginator.num_pages + 1)  # 左开右闭
        else:
            pageRange = range(currentPage - 3, currentPage + 4)
    else:
        pageRange = paginator.page_range

    try:
        obj_list = paginator.page(page)
    except PageNotAnInteger:
        obj_list = paginator.page(1)
    except EmptyPage:
        obj_list = paginator.page(paginator.num_pages)
    return obj_list, paginator, currentPage, pageRange


@login_required
def cn_backend(request):
    user_obj = request.user
    username = user_obj.username
    blog = user_obj.blog
    article_list = models.Article.objects.filter(user=user_obj)

    # 调用分页函数
    article_list, paginator, currentPage, pageRange = page_util(request, article_list, 5)

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


@login_required
def add_article(request):
    user = request.user
    if request.method == "GET":
        form_obj = MyForms.ArticleForm(user=user)
        return render(request, "backend/add_article.html", {"form": form_obj})

    # 给form表单传入user参数,用来在初始化文章分类和标签时筛选出该用户名下的分类和标签
    form_obj = MyForms.ArticleForm(request.POST, user=user)
    if form_obj.is_valid():
        title = form_obj.cleaned_data.get("title")
        content = form_obj.cleaned_data.get("content")
        category_id = form_obj.cleaned_data.get("category")
        tag_id_list = form_obj.cleaned_data.get("tags")

        # 防止xss攻击,过滤script标签
        soup = BeautifulSoup(content, "html.parser")
        for tag in soup.find_all():
            if tag.name == "script":
                tag.decompose()

        # 构建摘要数据,获取标签字符串的文本前150个符号
        desc = soup.text[0:150] + "..."

        article_obj = models.Article.objects.create(title=title, desc=desc, content=str(soup),
                                                    category_id=category_id, user=user)

        # 绑定标签,因为是自建关系表,不能通过关联管理器操作。
        for tag_id in tag_id_list:
            models.Article2Tag.objects.create(article=article_obj, tag_id=tag_id)
        return redirect("/cn_backend/")

    else:
        return render(request, "backend/add_article.html", {"form": form_obj})


@login_required
def edit_article(request, article_id):
    article_obj = models.Article.objects.filter(pk=article_id).first()
    tag_id_list = list(article_obj.tags.all().values_list("pk"))
    # 格式转化:将[(1,), (2,)]转化为[1, 2]
    tag_id_list = [l[0] for l in tag_id_list]
    user = request.user
    if request.method == "GET":
        form_obj = MyForms.ArticleForm(
            user=user,
            initial={
                'title': article_obj.title,
                'content': article_obj.content,
                'category': article_obj.category.pk,
                'tags': tag_id_list,
            },
        )
        return render(request, "backend/edit_article.html", {"form": form_obj})

    form_obj = MyForms.ArticleForm(request.POST, user=user)
    if form_obj.is_valid():
        title = form_obj.cleaned_data.get("title")
        content = form_obj.cleaned_data.get("content")
        category_id = form_obj.cleaned_data.get("category")
        tag_id_list = form_obj.cleaned_data.get("tags")

        # 防止xss攻击,过滤script标签
        soup = BeautifulSoup(content, "html.parser")
        for tag in soup.find_all():
            if tag.name == "script":
                tag.decompose()

        # 构建摘要数据,获取标签字符串的文本前150个符号

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

        article_obj.title = title
        article_obj.desc = desc
        article_obj.content = str(soup)
        article_obj.category_id = category_id
        article_obj.user = user
        article_obj.save()

        # 绑定标签
        # 先清空原来绑定关系
        models.Article2Tag.objects.filter(article=article_obj).delete()
        # 再重新绑定新的关系
        for tag_id in tag_id_list:
            models.Article2Tag.objects.create(article=article_obj, tag_id=tag_id)

        return redirect("/cn_backend/")

    else:
        return render(request, "backend/eidt_article.html", {"form": form_obj})


@login_required
def del_article(request, article_id):
    models.Article.objects.filter(pk=article_id).delete()
    return redirect("/cn_backend/")


@login_required
def category(request):
    user_obj = request.user
    blog = user_obj.blog
    if request.method == "GET":
        # 查询当前站点的每一个分类名称以及对应的文章数
        cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(
            c=Count("article__title")).values_list(
            "title", "c", "pk")
        return render(request, "backend/edit_cate.html", {"cate_list": cate_list})

    response = {"flag": None, "msg": None}
    type = request.POST.get("type")
    title = request.POST.get("title")
    cate_pk = request.POST.get("cate_pk")  # 仅在更新时有值
    cate_obj = models.Category.objects.filter(title=title).first()
    if cate_obj:
        response["flag"] = False
        response["msg"] = "该分类已存在!"
    else:
        if type == "add":
            cate_new_obj = models.Category.objects.create(title=title, blog=blog)
            response["msg"] = "添加成功!"
        else:
            cate_new_obj = models.Category.objects.filter(pk=cate_pk).first()
            cate_new_obj.title = title
            cate_new_obj.blog = blog
            cate_new_obj.save()
            response["msg"] = "更新成功!"
        response["flag"] = True
        response["cate_pk"] = cate_new_obj.pk
    return JsonResponse(response)


@login_required
def del_category(request, category_id):
    models.Category.objects.filter(pk=category_id).delete()
    return redirect("/cn_backend/category/")


@login_required
def tags(request):
    user_obj = request.user
    blog = user_obj.blog
    # 查询当前站点的每一个分类名称以及对应的文章数
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(
        c=Count("article__title")).values_list("title", "c", "pk")
    return render(request, "backend/tags.html", {"tag_list": tag_list})


@login_required
def edit_tag(request):
    user_obj = request.user
    blog = user_obj.blog
    response = {"flag": None, "msg": None}
    tag_title = request.POST.get("tag_title")
    tag_type = request.POST.get("tag_type")
    if request.method == "POST":
        tag_new_obj = models.Tag.objects.filter(title=tag_title)
        if tag_new_obj:
            response["flag"] = False
            response["msg"] = "该标签已存在"
        else:
            if tag_type == "add":
                models.Tag.objects.create(title=tag_title, blog=blog)
            else:
                tag_id = request.POST.get("tag_id")
                tag_obj = models.Tag.objects.filter(pk=tag_id).first()
                tag_obj.title = tag_title
                tag_obj.save()
            response["flag"] = True
        return JsonResponse(response)


@login_required
def del_tag(request, tag_id):
    models.Tag.objects.filter(pk=tag_id).delete()
    return redirect("/cn_backend/tags/")


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

    img_obj = request.FILES.get("upload_img")

    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/{}".format(img_obj.name)
    }
    return HttpResponse(json.dumps(response))

创建模板

base.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客后台管理</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="/static/blog/css/backend.css">
</head>
<body>
    <div class="header">
        <p class="title">
            后台管理
            <a class="info" href="/logout/">注销</a>
            <a class="info" href="/">返回首页</a>
            <a class="info" href="/{{ request.user.username }}/">个人主页</a>
        </p>
    </div>

    <div class="container">
        <div class="col-md-2">
            <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
                <div class="panel panel-default">
                    <div class="panel-heading" role="tab" id="headingOne">
                        <h4 class="panel-title">
                            <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne"
                               aria-expanded="true" aria-controls="collapseOne">
                                操作
                            </a>
                        </h4>
                    </div>
                    <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
                        <div class="panel-body">
                            <p><a href="/cn_backend/add_article/">添加文章</a></p>
                            <p><a href="/cn_backend/category/">文章分类</a></p>
                            <p><a href="/cn_backend/tags/">标签管理</a></p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">
            <div>
                <!-- Nav tabs -->
                <ul class="nav nav-tabs" role="tablist">
                    <li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab"
                                                              data-toggle="tab">文章</a></li>
                    <li role="presentation"><a href="#profile" aria-controls="profile" role="tab"
                                               data-toggle="tab">日记</a></li>
                    <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">眼镜</a>
                    </li>
                    <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">相册</a>
                    </li>
                </ul>
                <!-- Tab panes -->
                <div class="tab-content">
                    <div role="tabpanel" class="tab-pane active" id="home">
                        {% block content %}
                        {% endblock %}
                    </div>
                    <div role="tabpanel" class="tab-pane" id="profile">
                        <img src="/static/blog/img/meinv2.jpg" alt="">
                        <img src="/static/blog/img/meinv3.jpg" alt="">
                        <img class="pull-right" src="/static/blog/img/meinv.jpg" alt="">
                    </div>
                    <div role="tabpanel" class="tab-pane" id="messages">
                        <img width="180" height="180" src="/static/blog/img/hashiqi2.jpg" alt="">
                        <img width="180" height="180" src="/static/blog/img/dogg4.jpg" alt="">
                        <img width="180" height="180" src="/static/blog/img/linhaifeng.jpg" alt=""><br>
                        <img width="180" height="180" src="/static/blog/img/dogg3.jpeg" alt="">
                        <img width="180" height="180" src="/static/blog/img/dogge2.jpg" alt="">
                        <img width="180" height="180" src="/static/blog/img/dogg5.jpg" alt="">
                    </div>
                    <div role="tabpanel" class="tab-pane" id="settings">
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

backend.html:

{% extends "backend/base.html" %}

{% block content %}
    <div class="article_list small">
        <table class="table table-hover table-striped">
            <thead>
            <tr>
                <th>标题</th>
                <th>文章分类</th>
                <th>评论数</th>
                <th>点赞数</th>
                <th>操作</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            {% for article in article_list %}
                <tr>
                    <td><a href="/{{ request.user.username }}/articles/{{ article.pk }}">
                        {{ article.title }}
                        </a>
                    </td>
                    <td>{{ article.category }}</td>
                    <td>{{ article.comment_count }}</td>
                    <td>{{ article.up_count }}</td>
                    <td><a class="text-primary" href="/cn_backend/edit_article/{{ article.pk }}">
                        编辑</a>
                    </td>
                    <td><a class="text-danger" href="/cn_backend/del_article/{{ article.pk }}">删除</a></td>
                </tr>
            {% endfor %}
            </tbody>
        </table>

        <div class="text-center">
            <ul class="pagination" id="pager">
                {% if article_list.has_previous %}
                    <li class="previous">
                        <a href="{{ current_path }}?page={{ article_list.previous_page_number }}">上一页</a>
                    </li>
                {% else %}
                    <li class="previous disabled"><a href="#">上一页</a></li>
                {% endif %}

                {% for num in pageRange %}
                    {% if num == currentPage %}
                        <li class="item active">
                            <a href="{{ current_path }}?page={{ num }}">{{ num }}</a>
                		</li>
                    {% else %}
                        <li class="item"><a href="{{ current_path }}?page={{ num }}">{{ num }}</a></li>
                    {% endif %}
                {% endfor %}

                {% if article_list.has_next %}
                    <li class="next">
                        <a href="{{ current_path }}?page={{ article_list.next_page_number }}">下一页</a>
                    </li>
                {% else %}
                    <li class="next disabled"><a href="#">下一页</a></li>
                {% endif %}
            </ul>
        </div>

    </div>
{% endblock %}

add_article.html:

{% extends "backend/base.html" %}

{% block content %}
    <form action="" method="post">
        {% csrf_token %}
        <div class="add_article">
            <div class="cnb-panel-header">添加文章</div>
            <div class="add_article_region">
                <div class="title form-group">
                    <label for="id_{{ form.title.name }}">{{ form.title.label }}</label>
                    {{ form.title }}<span class="pull-right error">{{ form.title.errors.0 }}</span>
                </div>
                <div class="content form-group">
                    <label for="article_content">{{ form.content.label }}</label>
                    {{ form.content }}
                    <span class="pull-right error">{{ form.content.errors.0 }}</span>
                </div>
                <div class="title form-group">
                    <label for="id_{{ form.category.name }}">{{ form.category.label }}</label>
                    {{ form.category }}<span class="pull-right error">{{ form.category.errors.0 }}</span>
                </div>
                <div class="title form-group">
                    <label for="id_{{ form.tags.name }}">{{ form.tags.label }}</label>
                    {{ form.tags }}<span class="pull-right error">{{ form.tags.errors.0 }}</span>
                </div>
                <input type="submit" class="btn btn-default">
            </div>
        </div>
    </form>
    <script charset="utf-8" src="/static/blog/kindeditor/kindeditor-all.js"></script>
    <script>
        KindEditor.ready(function (K) {
            window.editor = K.create('#id_content', {
                width: "800",
                height: "300",
                resizeType: 0,
                uploadJson: "/upload/",
                extraFileUploadParams: {
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                },
                filePostName: "upload_img"
            });
        });
    </script>
{% endblock %}

edit_article.html:

{% extends "backend/base.html" %}

{% block content %}
    <form action="" method="post">
        {% csrf_token %}
        <div class="add_article">
            <div class="alert-success text-center">编辑文章</div>
            <div class="add_article_region">
                <div class="title form-group">
                    <label for="id_{{ form.title.name }}">{{ form.title.label }}</label>
                    {{ form.title }}<span class="pull-right error">{{ form.title.errors.0 }}</span>
                </div>
                <div class="content form-group">
                    <label for="id_content">{{ form.content.label }}</label>
                    {{ form.content }}
                    <span class="pull-right error">{{ form.content.errors.0 }}</span>
                </div>
                <div class="title form-group">
                    <label for="id_{{ form.category.name }}">{{ form.category.label }}</label>
                    {{ form.category }}<span class="pull-right error">{{ form.category.errors.0 }}</span>
                </div>
                <div class="title form-group">
                    <label for="id_{{ form.tags.name }}">{{ form.tags.label }}</label>
                    {{ form.tags }}<span class="pull-right error">{{ form.tags.errors.0 }}</span>
                </div>
                <input type="submit" class="btn btn-default">
            </div>
        </div>
    </form>
    <script charset="utf-8" src="/static/blog/kindeditor/kindeditor-all.js"></script>
    <script>
        KindEditor.ready(function (K) {
            window.editor = K.create('#id_content', {
                width: "800",
                height: "300",
                resizeType: 0,
                uploadJson: "/upload/",
                extraFileUploadParams: {
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                },
                filePostName: "upload_img"
            });
        });
    </script>
{% endblock %}

edit_cate.html:

{% extends "backend/base.html" %}

{% block content %}
    <div class="cnb-panel-header">
        <span>编辑分类</span>
    </div>
    <div class="category_list small">
        <table class="table table-hover table-striped" id="cate_table">
            <thead>
            <th>文章分类</th>
            <th>文章数</th>
            <th>操作</th>
            <th>操作</th>
            </thead>
            <tbody>
            {% for cate in cate_list %}
                <tr>
                    <td>{{ cate.0 }}</td>
                    <td>{{ cate.1 }}</td>
                    <td><a class="text-primary edit_cate" index="{{ cate.2 }}" >编辑</a></td>
                    <td><a class="text-danger" href="javascript:void(0)" 
                           onclick="showDeleteModal(this)" index="{{ cate.2 }}">删除</a></td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
            <!-- 模态框   信息删除确认 -->
            <div class="modal fade" id="delcfmOverhaul">
                <div class="modal-dialog">
                    <div class="modal-content message_align">
                        <div class="modal-header">
                            <button type="button" class="close" data-dismiss="modal"
                                    aria-label="Close">
                                <span aria-hidden="true">×</span>
                            </button>
                            <h4 class="modal-title">提示</h4>
                        </div>
                        <div class="modal-body">
                            <!-- 隐藏需要删除的id -->
                            <input type="hidden" id="deleteHaulId"/>
                            <p>该分类下有<span id="article_count"></span>篇文章,</p>
                            <p>您确认要删除吗?</p>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default"
                                    data-dismiss="modal">取消
                            </button>
                            <button type="button" class="btn btn-primary"
                                    id="deleteHaulBtn">确认
                            </button>
                        </div>
                    </div>
                    <!-- /.modal-content -->
                </div>
                <!-- /.modal-dialog -->
            </div>
    </div>
    <hr>
    <div class="cnb-panel-header">
        <span id="cate_head">新增分类</span>
    </div>
    <form>
        {% csrf_token %}
        <div class="form-group">
            <label for="cate_tile">分类名称</label>
            <input type="text" name="cate_title" id="cate_tile" class="form-control">
            <span class="error" id="cate_error"></span>
        </div>
        <input type="button" class="btn btn-default" id="cate_btn" value="提交">
    </form>
    <script>
        var cate_pk = "";
        var cate_type = "add";
        $("#cate_tile").focus(function () {
            $("#cate_error").html("");
        })
        $("#cate_btn").click(function () {
            var cate_title = $("#cate_tile").val()
            console.log(cate_title.length);
            if (cate_title) {
                if (cate_title.length > 16) {
                    $("#cate_error").html("名称太长了!");
                } else {
                    $.ajax({
                        url: "/cn_backend/category/",
                        type: "POST",
                        data: {
                            "type": cate_type,
                            "title": cate_title,
                            "cate_pk": cate_pk,
                            "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                        },
                        success: function (data) {
                            if (data.flag) {
                                if (cate_type === "add") {
                                         // 异步添加记录到表格中

                                    var tr_s = `
                                     <tr>
                                         <td>${cate_title}</td>
                                         <td>0</td>
                                         <td><a href="/cn_backend/edit_category/${data.cate_pk}">
												编辑
                                        	</a>
                                        </td>
                                         <td><a href="/cn_backend/del_category/${data.cate_pk} ">删除
        									</a>
        								</td>
                                      </tr>`

                                    $("#cate_table>tbody").append(tr_s);

                                       //清空输入框
                                    $("#cate_tile").html("");
                                    cate_pk = "";
                                    cate_type = "add";
                                } else {
                                    location.reload();
                                }
                            } else {
                                $("#cate_error").html("该分类已存在!");
                            }
                        }

                    })
                }
            } else {
                $("#cate_error").html("文章分类不能为空!");
            }
        })
        $(".edit_cate").click(function () {
            cate_pk = $(this).attr("index");
            cate_type = "update";
            var cate_title = $(this).parent().parent().find("td").eq(0).text();
            $("#cate_head").html("编辑分类");
            $("#cate_tile").val(cate_title);
        })

        // 打开询问是否删除的模态框并设置需要删除的ID
        function showDeleteModal(obj) {
            var $tds = $(obj).parent().parent().children();// 获取到所有列
            console.log($($tds[1]).text());
            var article_count = $($tds[1]).text();// 获取文章数量
            var delete_id = $($tds[3]).children("a").attr("index");// 获取隐藏的ID
            console.log(delete_id);
            $("#deleteHaulId").val(delete_id);// 将模态框中需要删除的ID设为需要删除的ID
            $("#article_count").text(article_count);
            $("#delcfmOverhaul").modal({
                backdrop: 'static',
                keyboard: false
            });
        }

        function deleteHaulinfo() {
            var del_id = $("#deleteHaulId").val();
            $.ajax({
                url: "cn_backend/del_category/" + del_id,
                type: "GET",
                success: function () {
                    location.reload();
                }
            })

        }

        // 删除模态框的确定按钮的点击事件
        $("#deleteHaulBtn").click(function () {
            // ajax异步删除
            deleteHaulinfo();
        });
    </script>
{% endblock %}

tags.html:

{% extends "backend/base.html" %}

{% block content %}
    <div class="cnb-panel-header">
        <span>标签管理</span>
    </div>
    <div>
        <button class="btn btn-primary pull-right" id="add_tag" onclick="showAddModal(this)">新增标签				</button>
    </div>
    <div class="tag_list small">
        <table class="table table-hover table-striped" id="tab_table">
            <thead>
            <th>标签</th>
            <th>文章数</th>
            <th>操作</th>
            <th>操作</th>
            </thead>
            <tbody>
            {% for tag in tag_list %}
                <tr>
                    <td>{{ tag.0 }}</td>
                    <td>{{ tag.1 }}</td>
                    <td><a class="text-primary edit_cate"  href="javascript:void(0)" 
                           onclick="showEditModal(this)" index="{{ tag.2 }}" >编辑</a></td>
                    <td><a class="text-danger" href="/cn_backend/del_tag/{{ tag.2 }}"  index="{{ tag.2 }}">							删除</a>
                    </td>
                </tr>
            {% endfor %}
            </tbody>
            <!-- 模态框  -->
            <div class="modal fade" id="editTagModal">
                <div class="modal-dialog">
                    <div class="modal-content message_align">
                        <div class="modal-header">
                            <button type="button" class="close" data-dismiss="modal"
                                    aria-label="Close">
                                <span aria-hidden="true">×</span>
                            </button>
                            <h4 class="modal-title" >编辑标签</h4>
                        </div>
                        <div class="modal-body">
                            <form >
                                {% csrf_token %}
                                <div class="form-group">
                                    <label for="tag_title">标签名称</label>
                                    <input type="text" name="tag_title" id="tag_title" class="form-control">
                                    <span class="error" id="cate_error"></span>
                                </div>
                            </form>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default"
                                    data-dismiss="modal">取消
                            </button>
                            <button type="button" class="btn btn-primary"
                                    id="editBtn">确认
                            </button>
                        </div>
                    </div>
                    <!-- /.modal-content -->
                </div>
                <!-- /.modal-dialog -->
            </div>
        </table>
    </div>
    <hr>
    <script>
        var tag_id = "";
        var tag_title = "";
        var tag_type   ="";
        // 打开编辑模态框
        function showEditModal(obj) {
            $(".modal-title").html("编辑标签");
            tag_type = "edit";
            var $tds = $(obj).parent().parent().children();// 获取到所有列
            tag_title = $($tds[0]).text();// 获取标签名称
            tag_id = $($tds[2]).children("a").attr("index");// 获取隐藏的ID
            $("#tag_title").val(tag_title);
            $("#editTagModal").modal({
                backdrop : 'static',
                keyboard : false
            });
        };

        // 打开新增模态框
        function showAddModal(obj) {
            $(".modal-title").html("新增标签");
            tag_type = "add";
            $("#editTagModal").modal({
                backdrop : 'static',
                keyboard : false
            });
        };
        function editinfo() {
            $.ajax({
                url:"/cn_backend/edit_tag/",
                type:"post",
                data:{
                    "tag_id":tag_id,
                    "tag_type":tag_type,
                    "tag_title":$("#tag_title").val(),
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val(),
                },
                success:function (data) {
                    if(data.flag){
                        location.reload();
                    }else{
                        var myVar;
                        clearTimeout(myVar);
                        $("#cate_error").text(data.msg);
                        myVar= setTimeout(function () {
                            $("#cate_error").text("");
                        },2000)
                    }

                }
            })

        };
        $(function () {
            // 删除模态框的确定按钮的点击事件
            $("#editBtn").click(function() {
                // ajax异步编辑
                editinfo();
            });
        })
    </script>
{% endblock %}

小技巧:

使用同一个模态框,通过修改模态框title实现新增和更新功能。

效果展示

后台管理主页:

在这里插入图片描述

新增文章页:

在这里插入图片描述

修改文章页:

在这里插入图片描述

文章分类页:

在这里插入图片描述

标签管理页:

在这里插入图片描述

未完待续

学python,找路飞!更多精彩,尽在路飞学城

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值