vlambda博客
学习文章列表

Vue.js前端加Django后端尝试(2)

目前的效果,首页只显示了轮播图,板块页面可以显示分类,点击分类相应显示对应分类的文章,点击文章链接可以到单篇文章详情。

环境说明一下:

Python 3.7

Django 2.2.3

simpleui 3.9

1.Django方面:

Django创建项目webproject,新建app mysite,

webproject/webproject/settings.py中,添加simpleui,用于Django admin后台。

INSTALLED_APPS = [
   'simpleui',
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'mysite.apps.MysiteConfig',
]

MIDDLEWARE注释掉'django.middleware.csrf.CsrfViewMiddleware',

小项目练手,数据库暂用自带的sqlite3,

DATABASES = {
   'default': {
       'ENGINE': 'django.db.backends.sqlite3',
       'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
  }
}

webproject/webproject/urls.py,api/用于接收前端请求,

from django.contrib import admin
from django.urls import path, include
from mysite import urls

urlpatterns = [
   path('admin/', admin.site.urls),
   path('api/', include("mysite.urls")),
]

之后转发webproject/mysite/urls.py继续处理。

from django.contrib import admin
from django.urls import path
from mysite import views

urlpatterns = [
   path('get_info/', views.get_info),  # 提供数据接口
   path('category/', views.get_info_by_category),
   path('get_doc/', views.get_doc_by_id),
]

models.py进行分类及文章的结构设计。

预想的是按照大类,小类分文章类别,做了二层目录,文章加一个首页轮播标记,通过标记选择哪些文章上首页轮播图。

class Category(models.Model):
   CATEGORY_TYPE = (
      (1, "一级目录"),
      (2, "二级目录"),
  )
   id = models.AutoField(primary_key=True)
   category_name = models.CharField(max_length=50, null=False, verbose_name="分类名称")
   category_code = models.CharField(default='01', max_length=50, null=False, verbose_name="分类代码")
   category_desc = models.CharField(default="分类描述", max_length=50, null=False, verbose_name="分类描述")
   category_type = models.IntegerField(default=1, choices=CATEGORY_TYPE, verbose_name="类目级别", help_text="类目级别")
   parent_category = models.ForeignKey("self", null=True, blank=True, verbose_name="父类目级别", help_text="父目录",
                                       related_name="sub_cat", on_delete=models.CASCADE)
   is_tab = models.BooleanField(default=False, verbose_name="是否导航", help_text="是否导航")

   def __str__(self):
       return self.category_name

   class Meta:
       verbose_name_plural = "目录"


class Content(models.Model):
   id = models.AutoField(primary_key=True)
   title = models.CharField(max_length=255)
   click_num = models.IntegerField(default=0, verbose_name="浏览次数")
   content = models.TextField()
   category = models.ForeignKey(Category, on_delete=models.CASCADE)
   user = models.ForeignKey(User, verbose_name="作者", on_delete=models.CASCADE)
   time = models.DateTimeField(auto_now_add=True)
   is_new = models.BooleanField(default=False, verbose_name="新文章")
   is_banner = models.BooleanField(default=False, verbose_name="首页轮播")

   def __str__(self):
       return self.title

   class Meta:
       verbose_name_plural = "文章内容"

views.py

from django.http import JsonResponse

get_info用于获取文章分类和取文章列表,如果带category标记,取文章分类,如果带有banner标记,取的是首页轮播文章,否则取所有文章。

def get_info(request):
   print("get_info request = ", request)
   if request.method == "GET":
       category_list = request.GET.get("category")
       get_blog_list = request.GET.get("blog_list")
       get_banner = request.GET.get("banner")

       if category_list is not None:
           db = Category.objects.filter(category_type=2)
           data = [
              {
                   "category_id": i.id,
                   "category_name": i.category_name,
                   "category_code": i.category_code,
              }
               for i in db]

           print(data)

           return JsonResponse({
               "status_code": 0,
               "data": data
          })

       if get_blog_list is not None and get_blog_list == "true":
           if get_banner is not None and get_banner == "true":
               db = Content.objects.filter(is_banner=True)
           else:
               db = Content.objects.all()
           data = [
              {
                   "id": i.id,
                   "title": i.title,
                   "time": i.time,
                   "click_num": i.click_num,
                   "content": i.content,
                   "category": i.category.category_name,
                   "user": i.user.username,
              }
               for i in db]

           return JsonResponse({
               "status_code": 0,
               "data": data
          })

get_info_by_category用于获取指定代码分类中的文章列表,如果分类号为0,取所有文章。

def get_info_by_category(request):
   category_id = request.GET.get("category_id")
   if category_id == '0' or category_id is None:
       db = Content.objects.all()
   else:
       db = Content.objects.filter(category__category_code=category_id)

   data = [
      {
           "id": i.id,
           "title": i.title,
           "time": i.time,
           "click_num": i.click_num,
           "category": i.category.category_name,
           "user": i.user.username,
      } for i in db]
       return JsonResponse({
       "status_code": 0,
       "data": data
  })

get_doc_by_id获取指定id的文章,

def get_doc_by_id(request):
   if request.method == "GET":
       doc_id = request.GET.get("doc_id")
       if doc_id is not None:
           db = Content.objects.filter(id=doc_id)
           if len(db)==0:
               return JsonResponse({
                   "status_code": 1,
                   "data": [
                      {
                           "id": doc_id,
                           "title": "错误的文章编号",
                           "time": "",
                           "click_num": 0,
                           "content": "",
                           "category_id": "",
                           "category_name": "",
                           "user": "",
                      }]
              })
           data = [
              {
                   "id": i.id,
                   "title": i.title,
                   "time": i.time,
                   "click_num": i.click_num,
                   "content": i.content,
                   "category_code": i.category.category_code,
                   "category_name": i.category.category_name,
                   "user": i.user.username,
              }for i in db]

           return JsonResponse({
               "status_code": 0,
               "data": data
          })

2.Vue方面:

前端项目vueproject创建在后端项目webproject的根目录下,

css太长,都删掉了。

后端主要就是Main主页,Category分类列表,Blog文章详情三块。Bloglist是之前的文章列表,暂时没用了。

module.exports = {
 dev: {

   // Paths
   assetsSubDirectory: 'static',
   assetsPublicPath: '/',
   proxyTable: {
     '/api':{
       target: 'http://127.0.0.1:8000/api',
       changeOrigin: true,
       pathRewrite:{
         '^/api':'',
      }
    }
  },

main.js导入需要的模块

import Vue from 'vue'
import App from './App'
import router from './router'
import VueResource from 'vue-resource'
import axios from 'axios'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import 'element-ui/lib/theme-chalk/display.css'
import Header from '@/components/Common/Header'
Vue.component(Header.name,Header)
import '../static/global/index.css'
//Vue -- axios 跨域请求无法带上cookie
axios.defaults.withCredentials = true

Vue.use(VueResource)
Vue.use(ElementUI);
Vue.use(axios);
Vue.config.productionTip = false
Vue.prototype.$axios = axios

/* eslint-disable no-new */
new Vue({
 el: '#app',
 router,
 components: { App },
 template: '<App/>'
})

App.vue 引用Index

<template>
 <!--elementui部分-->
 <div id="app">
   <Index />
 </div>

</template>

<script>
 import Index from './components/Index'

 export default {
   name: 'App',
   components:{
     Index
  },
 data() {
   return {
     activeIndex: '1',
     activeIndex2: '1',
  };
},
 methods: {
   handleSelect(key, keyPath) {
     console.log(key, keyPath);
  }
},

}
</script>

<style>

</style>

router/index.js 路由,导入所有的页面模块,设置访问路径。

import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/Index'
import Main from '@/components/Main'
import Category from '@/components/Category'
import Blog from '@/components/Blog'
import Bloglist from '@/components/Bloglist'
import User from '@/components/User'
import About from '@/components/About'

Vue.use(Router)

export default new Router({
 mode:'history',
 linkActiveClass:'is-active',
 routes: [
  {
     path: '/',
     name: 'Main',
     component: Main
  },
  {
     path: '/index',
     name: 'Index',
     component: Index
  },
  {
     path: '/blog/:id',
     name: 'Blog',
     component: Blog
  },
  {
     path: '/category',
     name: 'Category',
     component: Category
  },
  {
     path: '/bloglist/:id',
     name: 'Bloglist',
     component: Bloglist
  },
  {
     path: '/user',
     name: 'User',
     component: User
  },
  {
     path: '/about',
     name: 'About',
     component: About
  }
],

})

components/Index.vue 主页面,Header固定的标题栏,router-view切换主页面显示的内容。

<template>
 <div class="Index">
   <Header></Header>
       <el-container>
         <el-main :xs="24">
           <router-view></router-view>
         </el-main>
         <el-footer>
           <el-divider content-position="center">
             <router-link to="/about"><i class="el-icon-user"></i>zlldt 2020 </router-link>
           </el-divider>
         </el-footer>
       </el-container>
 </div>
</template>

<script>
 export default {
   name: 'Index',
   data () {
     return {
    }
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Common/Header.vue 标题栏,主页、板块。

<template>
   <el-container>
     <el-header>
       <div class="topmenubg">
       <ul id="nav" class="nav clearfix">
         <li class="nLi on" index="nav.id" v-for="nav in navlinks" :key="nav.id">
           <router-link :to="{name:nav.name}">
            {{nav.title}}
           </router-link>
         </li>
       </ul>
       </div>
     </el-header>
   </el-container>
</template>

<script>
   export default {
     name: "Header",
     data(){
       return {
         activeIndex:1,
         navlinks:[
          {id:1,title:'首页',name: 'Main'},
          {id:2,title:'板块',name: 'Category',params:{category_code:0}},
        ]
      }
    }
  }
</script>

<style scoped>
</style>

Main.vue首页,this.$axios.get("api/get_info?blog_list=true&banner=true")获取走马灯显示的文章。文章还没有带上图片,偷懒先全放同一张图片。

<template>
 <div class="Main">
   <div class="box1 clear">
   <!--走马灯-->
   <div class="xw left" >
     <el-carousel height="350px">
       <el-carousel-item v-for="item in Carousel" :key="item">
         <router-link :to="{name:'Blog', params:{id:item.id}}">
           <img src="../assets/mathicon100.png" height="100" width="100"/>
           <h3 class="small">{{ item.title }}</h3>
         </router-link>
       </el-carousel-item>
     </el-carousel>
   </div>
   <!--查看文章列表-->
   <div class="right">
   <ul class="card-content" v-for="dat in Blog":key="dat.title">
     <div slot="header" class="card-header-text">
       <router-link :to="{name:'Blog', params:{id:dat.id}}">
       <span style="font-size: 18px; font-weight: bolder">{{ dat.title }}</span>
       </router-link>
     </div>
   </ul>
   </div>
   </div>
 </div>
</template>

<script>
 export default {
   name: 'Main',
   data () {
     return {
       Carousel:[],
       Blog:[],
    }
  },
   created() {
     this.$axios.get("api/get_info?blog_list=true&banner=true")
      .then(response => {
         this.Carousel = response.data.data;
         this.Blog = response.data.data;
         this.loading = false
      }, error => {
         console.log("获取bloglist出错了.");
      });
  }
}
</script>

<style scoped>
</style>

Category.vue 获取分类列表,通过标签切换分类,显示对应的分类文章列表。

<template>
 <div class="Category">
   <div class="box2 clearfix" >
     <ul class="categorybox">
       <li @click="categoryHandler(index,category.category_code)" v-for="(category,index) in CategoryList" :key="category.category_id" :class="{active:currentIndex===index}">
        {{ category.category_name }}
       </li>
     </ul>
   </div>

   <!--bloglist-->
   <div class="blogList">
     <br>
     <table width="790" align="center" border="0" cellspacing="0" cellpadding="0" class="newlisttable"  v-for="dat in blogList" :key="dat.title">
       <tr>
         <td>
         <router-link :to="{name:'Blog', params:{id:dat.id}}">
           <span >{{ dat.title }}</span><!--style="font-size: 18px; font-weight: bolder"-->
         </router-link>
         <div style="float: right; font-size: 5px"> ({{ dat.time }})  </div><!-- -- {{ dat.user }} -- {{ dat.category}}-->
         </td>
       </tr>
       <br>
     </table>
     </el-card>
   </div>

 </div>
</template>

<script>
 export default {
   name: "Category",
   data() {
     return {
       CategoryList: [],//分类列表
       currentIndex:0,
       blogList:[],//文章列表
       categoryId:null,
    }
  },
   created() {
     this.getCategoryList();
     if (this.$route.params.category_id === 0){
       this.getBlogList(0);
    }
     else
       this.categoryId=this.$route.params.category_id;
       this.getBlogList(this.$route.params.category_id );
  },
   methods:{
     categoryHandler(index,category_code){
       this.currentIndex = index;
       this.categoryId = category_code;
       this.getBlogList(this.categoryId);
    },
     getCategoryList(){
       this.$axios.get("/api/get_info?category=true")
        .then(response => {
           this.CategoryList = response.data.data;
           let firstCategory={
             'category_id':0,
             'category_name':'全部',
             'category_code':0,
          };
           this.CategoryList.unshift(firstCategory);
        }, error => {
           console.log("获取CategoryList出错了.");
        });
    },
     getBlogList() {
       this.$axios.get('/api/category/',{
         params:{
           'category_id':this.categoryId
        }
      })
        .then(response => {
             this.blogList = response.data.data;
        }, error => {
           console.log("获取blog出错了.");
        });
    }
  }
}
</script>

<style scoped>
</style>

Blog.vue文章显示

<template>
 <div class="Blog">
   <div class="box3 clearfix" >
   <td valign="top">
     <div class="xw left" >
       <!--查看单篇文章-->
       <div class="pageconbk" v-for="dat in blog":key="dat.title">
         <div class="contenttitle">
           <span style="font-size: 18px; font-weight: bolder">{{ dat.title }}</span>
           <div style="float: right; font-size: 5px"> {{ dat.time }} -- {{ dat.user }} -- {{ dat.category_name}}  </div>
         </div>
         <div>
           <!--<span style="font-size: 10px">{{ dat.content }}</span>-->
           <span style="font-size: 10px"><p class="text-wrapper" v-html="dat.content"></p></span>
         </div>
       </div>
     </div>
   </td>
   <!--右侧导航-->
   <td valign="top">
     <div class="managestitle" v-for="dat in blog":key="dat.title">
       <div>{{dat.category_name}}</div>
     </div>
   </td>
   </div>
 </div>
</template>

<script>
 export default {
   name: "Blog",
   data() {
     return {
       blog: [],
       loading: false

    };
  },
   methods:{
     getArticleData() {
       this.$axios.get('/api/get_doc',{
         params:{
           'doc_id':this.$route.params.id
        }
    })
        .then(response => {
           this.blog = response.data.data;
           this.loading = false
        }, error => {
           console.log("获取blog出错了.");
        });
    }
  },
   beforeMount(){
     this.loading = true;
     this.getArticleData();
  }
}
</script>
<style scoped>
</style>


显示的效果,css还没仔细研究,先随便抄了下。

Vue.js前端加Django后端尝试(2)

还要再考虑的方面:

板块切换那里,怎么从文章链接返回对应的板块;

首页上应该要添加各个板块列表最新文章;

文章内容Markdown显示;

CSS。