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还没仔细研究,先随便抄了下。
还要再考虑的方面:
板块切换那里,怎么从文章链接返回对应的板块;
首页上应该要添加各个板块列表最新文章;
文章内容Markdown显示;
CSS。