用Django全栈开发——14. CMS中添加Category和Tag管理

大家好,这是皮爷给大家带来的最新的学习Python能干啥?之Django教程,从零开始,到最后成功部署上线的项目。这一节,来点硬货内容。

用Django全栈开发——14. CMS中添加Category和Tag管理_第1张图片

上一节,我们开发了文章应用,创建了Post,Category还有Tag这三个类。这一节,我们就要在CMS页面里面,来实现Category还有Tag的管理功能。

重构Dashboard

在第12讲,我们重构了首页页面,这一节,我们的重点是CMS的Dashboard页面,所以,我们需要将Dashboard重构。重构的思路还是和之前Index.html重构思路一样,即通过使用extend,block还有include,来讲整个页面拆分成几个模块,每一个页面都是通过模块模块之间的组合,所以,我们要在CMS下面创建一个base文件夹,重构完之后,整个目录结构应该是这个样子的:

用Django全栈开发——14. CMS中添加Category和Tag管理_第2张图片

这里base目录下,有三个东西,dashboard_base则是dashboard最基本的,navbar则是顶部的Navbar导航栏,sidebar则是左侧的Sidebar菜单列。

这个dashboard_base文件结构就成了下面这样:


<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Peekpa | Dashboard | {% block title %}

    {% endblock %}title>
    
    {% block head %}

    {% endblock %}
head>

<body class="hold-transition sidebar-mini layout-fixed">
<div class="wrapper">
    
    {% include 'cms/base/navbar.html' %}
    
    
    {% include 'cms/base/sidebar.html' %}

    
    <div class="content-wrapper">
        {% block main %}

        {% endblock %}
    div>
div>



body>
html>

可以看到这里我们使用了三个blcok,分别是title,head还有main。这一点和首页是一样的。同时,还用了两个include标签,分别将navbar还有sidebar引入进来。

我们把原来的Dashboard.html抽象到了home.html文件中:

{% extends 'cms/base/dashboard_base.html' %}

{% block title %}
Home
{% endblock %}

{% block head %}

{% endblock %}

{% block main %}


<section class="content">
    <div class="container-fluid">
        <div class="row d-flex justify-content-around pt-4 mb-4">
            <p class="h3">《用Django全栈开发——14. CMS中添加Category和Tag管理》p>
            <p class="h5">公众号『皮爷撸码』,连载更新此系统的开发教程,敬请关注p>
        div>
        <div class="row d-flex justify-content-around">
            <img class="img-thumbnail" src="https://www.peekpa.tech/asserts/img/qrcode.jpg" alt="">
        div>
    div>
section>

{% endblock %}

可以看到,这里首先使用extend来继承dashboard_base文件,然后填充里面的block内容。最后,我们继承完成的首页,就长这个样子:

用Django全栈开发——14. CMS中添加Category和Tag管理_第3张图片

Category开发

我们开发Category的思路也很简单,就只有两个页面:管理页面还有发布页面。

管理页面就是一张表格,里面显示的Category的基本信息;发布页面则是要发布Category。所以,我们创建Category目录,并在目录下创建两个文件,manage.htmlpublish.html文件,分别对应的管理和发布。当然,这两个文件的开发思路和home是一样的,都需要继承dashboard_base文件。

所以,我们先把manage.htmlpublish.html两个文件的结构先创建起来:


{% extends 'cms/base/dashboard_base.html' %}

{% block head %}

{% endblock %}

{% block title %}
    Category Management
{% endblock %}

{% block main %}
    <section class="content">
        <div class="container-fluid pt-4">
            <div class="row">
                <div class="col-sm-12">
                    <div class="card">
                        <div class="card-body">
                            <div class="row p-2 d-flex justify-content-between">
                                <p class="h3">Categoriesp>
                                <div class="float-right">
                                    <a class="btn btn-primary text-right" href=""><i class="mr-2 fas fa-plus">i>Adda>
                                div>
                            div>
                            <table class="table table-bordered table-hover">
                                <thead class="thead-light">
                                    <tr>
                                        <th style="width: 10%;">#th>
                                        <th>tag_nameth>
                                        <th>create_timeth>
                                        <th class="w-25">actionsth>
                                    tr>
                                thead>
                                <tbody>
                                    <tr>
                                        
                                    tr>
                                tbody>
                            table>
                        div>
                    div>
                div>
            div>
        div>
    section>

{% endblock %}



{% extends 'cms/base/dashboard_base.html' %}

{% block title %}
Category Publish
{% endblock %}

{% block main %}
    <section class="content">
        <div class="container-fluid">
            <div class="row d-flex justify-content-center pt-4">
                <div class="col-sm-6">
                    <div class="card card-primary">
                        <div class="card-header">
                        <h3 class="card-title">Tag Publishh3>
                        div>
                        
                        <form class="form-horizontal" method="post">
                            {% csrf_token %}
                            <div class="card-body">
                                <div class="form-group row mb-0">
                                    <label for="inputEmail3" class="col-form-label col-sm-2 text-center">Namelabel>
                                    <div class="col-sm-10">
                                        <input type="text" class="form-control" id="name" name="name">
                                    div>
                                div>
                            div>
                            
                            <div class="card-footer">
                                <button type="submit" class="btn btn-info" name="submit">Submitbutton>
                                <button type="submit" class="btn btn-danger float-right" name="cancel">Cancelbutton>
                            div>
                            
                        form>
                    div>
                div>
            div>

        div>
    section>
{% endblock %}

可以看到,两个html文件的格式都非常简单:一个是里面添加了一个table,用来展示数据;另一个则是只有一个form表单,用来提交数据。

接下来,我们还需要在CMS应用中,来创建这两个视图文件的映射,很简单,在CMS目录下的views.py文件,添加两个函数:

def category_manage_view(request):
    return render(request, 'cms/category/manage.html')

def category_publish_view(request):
    return render(request, 'cms/category/publish.html')

在urls.py文件中,将这两个视图函数映射到URL上:

urlpatterns = [
    #前面的内容省略,下面两个是新家的内容
    path("dashboard/category/manage", views.category_manage_view, name="category_manage_view"),
    path("dashboard/category/publish", views.category_publish_view, name="category_publish_view"),
]

这样,我们就完成了映射:http://localhost:8000/cms/dashboard/category/manage对应的是Category Manage页面;http://localhost:8000/cms/dashboard/category/publish对应的是Category Publish页面。

如果想要方便的看我们的页面,我们还得修改一下左侧的Sidebar,分别将这两个URL对应进去,这个简单,只需要在sidebar.html文件中修改即可:

<li class="nav-header">CATEGORYli>
<li class="nav-item">
    <a href="{% url 'cms:category_manage_view' %}" class="nav-link">
        <i class="nav-icon fas fa-list">i>
        <p>
            Category Management
        p>
    a>
li>
<li class="nav-item">
    <a href="{% url 'cms:category_publish_view' %}" class="nav-link">
        <i class="nav-icon far fa-plus-square">i>
        <p>
            Category Publish
        p>
    a>
li>

此时,我们启动服务,来查看一下我们的页面。Manage页面:

用Django全栈开发——14. CMS中添加Category和Tag管理_第4张图片

Publish页面;

用Django全栈开发——14. CMS中添加Category和Tag管理_第5张图片

目前只是样子搭建完成,功能还没有做。接下来我们来说功能的事儿。

Category功能开发

关于Category的功能,其实很简单,目前就这么几条:

  • 新增Category;
  • 读取所有的Category;
  • 修改Category;
  • 删除Category。

这几条其实也就是传说中的CRUD。我们首先来看新增功能。

Category的新增

新增功能的页面,自然是在Category Publish中,函数的编写地方则应该是在CMS应用中。首先明确一点,我们的Category Publish页面中的form表单,是要发送POST请求。所以,我们应该在CMS目录下创建一个forms.py文件,在里面填写表单,然后再创建一个category_view.py文件,在这个里面写视图函数。为啥要单独在创建一个Category View文件?是因为这样我们方便管理。

Forms.py文件里面的CategoryForm:

class CategoryForm(forms.ModelForm, FormMixin):
    class Meta:
        model=Category
        fields = "__all__"

Category_view.py文件里面的内容:

class CategoryView(View):
    def post(self, request):
        form = CategoryForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data.get('name')
            Category.objects.create(name=name)
            return redirect(reverse("cms:category_publish_view"))

可以看到,这里我们直接调用的Category.objects.create(name=name)方法来保存数据,接下来,我们尝试一下:

用Django全栈开发——14. CMS中添加Category和Tag管理_第6张图片

我们在publish这里输入123,然后点击submit:

用Django全栈开发——14. CMS中添加Category和Tag管理_第7张图片

看到POST请求已经发送出去了,接下来我们去数据库里面看一下:

用Django全栈开发——14. CMS中添加Category和Tag管理_第8张图片

数据库里面成功的有了name为123的数据,说明我们的添加功能已经完成了。

接下来我们去完成一下读取的过程,即将数据库里面的数据都读取出来,放到Manage页面里:

Category的读取

编写逻辑即在我们的manage.html的加载时候,做一下数据库的读取操作,然后将读取的到的Category全部返回到页面中。所以我们就要修改cms目录下的views.py文件里的category_manage_view(request)函数了,让他读取所有的Category数据:

def category_manage_view(request):
    context = {
     
        "list_data": Category.objects.all()
    }
    return render(request, 'cms/category/manage.html', context=context)

这里我们使用context来传递给前端,当然,前端的publish.html页面也得修改,即在tbody标签里面,添加Django模板的for循环:

<tbody>
    {% for item in list_data %}
        <tr>
            <td>{
    { item.id }}td>
            <td>{
    { item.name }}td>
            <td>{
    { item.create_time }}td>
            <td>
                <a href="#" class="btn btn-info btn-xs">Modifya>
                <button class="btn btn-danger btn-xs delete-btn" data-pk-id="{
      { javcode.pk }}">
                    Delete
                button>
            td>
        tr>
    {% endfor %}
tbody>

我们在数据库里面分别添加了Python开发和关注皮爷撸码两条数据,我们再来看一下前端的显示:

用Django全栈开发——14. CMS中添加Category和Tag管理_第9张图片

完美显示,说明读取工作也做完了。

Category的修改

这里的所说的修改,是指在Manage页面,我们如果要修改比如第一条数据的name,我们需要系统提供改名字的服务。

为了更好的偷懒,不对,是重复利用,我们可以试用publish页面的内容来提供修改。做法只需要:

  • 首先在manage页面的modify配置好修改的url,并且传入参数;
  • 其次就是在publish页面,需要修改到能配合参数传入,并且显示出来;
  • 最后一步就是处理publish页面的submit逻辑。

首先我们要修改publish.html文件的form结构:


<form class="form-horizontal" action="{% url 'cms:category_add' %}" method="post">
    {% csrf_token %}
    {% if item_data %}
        <input type="text" class="form-control" id="pk" name="pk" value="{
      { item_data.id }}" hidden>
    {% endif %}
    <div class="card-body">
        <div class="form-group row mb-0">
            <label for="inputEmail3" class="col-form-label col-sm-2 text-center">Namelabel>
            <div class="col-sm-10">
                {% if item_data %}
                    <input type="text" class="form-control" id="name" name="name" value="{
      { item_data.name }}">
                {% else %}
                    <input type="text" class="form-control" id="name" name="name">
                {% endif %}
            div>
        div>
    div>
    
    <div class="card-footer">
        {% if item_data %}
            <button type="submit" class="btn btn-info" name="modify">Submitbutton>
            <button type="submit" class="btn btn-danger float-right" name="cancel">Cancelbutton>
        {% else %}
            <button type="submit" class="btn btn-info" name="submit">Submitbutton>
            <button type="submit" class="btn btn-danger float-right" name="back">Backbutton>
        {% endif %}
    div>
    
form>

我们看到这里为了复用publish.html,我们使用的Django模板的if标签,用来判断后台是否传入了Category data,如果传入了,就将Category的ID还有name显示到表格中,如果没有,一切如初。

还有一点就是最后的submit按钮也做了修改,根据是否有数据, 做了4个按钮,分别对应不同的数据处理逻辑,可以看到这4个button的name不一样,分别是modify, cancel, submit和back。为啥要分成4个?是因为在request.post请求的时候,我们会将按钮的name传入给后台,通过name不一样,我们就能处理不同的逻辑:

用Django全栈开发——14. CMS中添加Category和Tag管理_第10张图片

这个时候,我们再重新组织一下CategoryView的post逻辑:

class CategoryView(View):
    def post(self, request):
        # 新建提交
        if 'submit' in request.POST:
            form = CategoryForm(request.POST)
            if form.is_valid():
                name = form.cleaned_data.get('name')
                Category.objects.create(name=name)
                return redirect(reverse("cms:category_publish_view"))
            else:
                return restful.method_error("Form is error", form.get_errors())
        # 修改Category
        elif 'modify' in request.POST:
            form = CategoryEditForm(request.POST)
            if form.is_valid():
                pk = form.cleaned_data.get('pk')
                name = form.cleaned_data.get('name')
                Category.objects.filter(id=pk).update(name=name)
                return redirect(reverse("cms:category_manage_view"))
            else:
                return restful.method_error("Form is error", form.get_errors())
        # 修改状态返回
        elif 'back':
            return redirect(reverse("cms:category_manage_view"))
        # 新建状态的取消
        else:
            return redirect(reverse("cms:category_publish_view"))

这里要说明一下,由于我们的Category的修改和创建,前端的表单传过来数据是不一样的:修改有id,创建没有id。所以这里我们又创建了另外的一个CategoryEditForm,里面就多了一个pk值而已:

class CategoryEditForm(forms.ModelForm, FormMixin):
    pk = forms.CharField(max_length=100)
    class Meta:
        model=Category
        fields = "__all__"

在上面的代码中,就能很清楚的看到,通过不同的request.POST里面的button name,做出了不同的处理。这时候,我们编写完成,再来前端实验一下,我们将第一条数据的name的值123修改为1234:

用Django全栈开发——14. CMS中添加Category和Tag管理_第11张图片

点击modify,将会来到修改页面:

用Django全栈开发——14. CMS中添加Category和Tag管理_第12张图片

点击提交,就会回到list页面:

用Django全栈开发——14. CMS中添加Category和Tag管理_第13张图片

这个时候看到,数值变成了1234,说明成功了!

Category的删除

删除很好操作,只需要完成一个删除函数就可以,同时配置好url就行。我们直接写一个删除的函数:

class CategoryDeleteView(View):
    def post(self,request):
        category_id = request.POST.get('category_id')
        print("category_id :", category_id)
        Category.objects.filter(id=category_id).delete()
        return redirect(reverse("cms:category_manage_view"))

然后将它绑定到urls.py文件中:

path("dashboard/category/delete", CategoryDeleteView.as_view(), name="category_delete"),

这个时候就会发现,我们的方法是写到了reqest.POST中了,这个时候,我们就要修改一下前端的代码,将删除按键绑定到JavaScript上了,这个时候就要引入一下js文件了:

function CMSCategory() {
     

}

CMSCategory.prototype.listenDeleteEvent = function () {
     
    var deleteBtns = $(".delete-btn");
    deleteBtns.click(function () {
     
        var btn = $(this);
        var category_id = btn.attr('data-category-id');
        peekpaajax.post({
     
            'url': '/cms/dashboard/category/delete',
            'data': {
     
                'category_id': category_id
            },
            'success': function (result) {
     
                if(result['code'] === 200){
     
                    window.location = window.location.href;
                    // window.location.reload()
                }
            }
        });
    });
};

CMSCategory.prototype.run = function () {
     
    this.listenDeleteEvent();
};

$(function () {
     
    var category = new CMSCategory();
    category.run();
});

别忘了最后在manage.html顶部的head block里面,把js文件引入:

<script src="{% static 'js/category.min.js' %}">script>

这里有一点注意:
$ is not defined错误发生,是应该把dashboard_base.html文件里面,body最后的script中的jQuery的引入,提前到head block前。具体不懂的,可以去看我的dashboard_base.html的head部分源码还有category/manage.html的源码

这里我们使用了一个peekpaajax,这个其实是我封装的一层Ajax,这里的逻辑是如果返回200,即成功,就刷新页面。

然后我们编写delete的视图函数:

class CategoryDeleteView(View):
    def post(self,request):
        category_id = request.POST.get('category_id')
        Category.objects.filter(id=category_id).delete()
        return restful.ok()

在urls.py里面配置路径:

urlpatterns = [
    path("dashboard/category/delete", CategoryDeleteView.as_view(), name="category_delete"),
]

这个时候我们来试验一下,我们删除第一条数据:

用Django全栈开发——14. CMS中添加Category和Tag管理_第14张图片

然后我们点击第一条数据的delete:

用Django全栈开发——14. CMS中添加Category和Tag管理_第15张图片

发现数据被删除了,可以看到ID没有了,我们再来数据库里面看一下:

用Django全栈开发——14. CMS中添加Category和Tag管理_第16张图片

确实是删除了。

至此,我们的Category的增删改查都开发完成。

剩下的Tag的增删改查,因为和Category一模一样,所以我们就不说了。

技术总结

最后总结一下,

Category和Tag的管理开发:

  1. 增加:写视图函数,发送post请求,使用form表单处理,最后保存到数据库中;
  2. 删除:使用到了JavaScript,通过Ajax发送Post请求;
  3. 修改:复用Publish.html,是否传入item_data来判断是否是修改还是添加;
  4. 查询:读取数据看,然后将结果放到context中,返回给页面;
  5. 完毕。

整套教程源码获取,可以关注『皮爷撸码』,回复『peekpa.com』

长按下图二维码关注,如文章对你有启发,欢迎转发。
用Django全栈开发——14. CMS中添加Category和Tag管理_第17张图片

你可能感兴趣的:(Django,Peekpa.com,Python,python,django,web)