文章目录
- 1.新建数据模型
- 2.新建数据序列类
- 3.新建数据视图
- 4.配置路由
- 5.前端新建View组件
- 6.配置后台
- 7.总结
django-vue-admin是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
🧑🤝🧑前端采用D2Admin 、Vue、ElementUI。
👭后端采用 Python 语言 Django 框架以及强大的 Django REST Framework。
👫权限认证使用Django REST Framework SimpleJWT,支持多终端认证系统。
👬支持加载动态权限菜单,多方式轻松权限控制。
💏特别鸣谢:D2Admin 、Vue-Element-Admin。
这套系统需要Django的基础知识,REST Framework框架的基础理解以及D2Admin的基础理解。本文从头开始简易说明如何用dvadmin管理一张数据表。
1.新建数据模型
处理数据是计算机最初开始的地方。在Django中,称为数据模型。声明如下:
class UserIPStatistics(CoreModel):#CoreModel 是dvadmin的核心字段,含用户信息
ip = models.CharField(max_length=255, verbose_name='IP', help_text="IP")
num = models.IntegerField( verbose_name='完成次数', help_text="完成次数", blank=True, default=0)
class Meta:
db_table = table_prefix + "UserStatistics"
verbose_name = '用户使用次数'
verbose_name_plural = verbose_name
ordering = ('-create_datetime',)
2.新建数据序列类
将用户ID转为用户名,方便在前端显示。
#用户统计序列化
class UserIPStatisticsSerializer(serializers.ModelSerializer):
#自定义字段
creator = serializers.SerializerMethodField();
zl_user=serializers.CharField(source="creator");#自定义字段
#转为用户名
def get_creator(self, obj):
try:
rlt=obj.creator.username;
return rlt;
except Exception as e:
return ""
class Meta:
model = UserIPStatistics
fields = '__all__'
read_only_fields = ('id', 'zl_user')
3.新建数据视图
指明查询集,序列化类和权限验证类。与文章开始的图保持一致。
# IP统计数据
class UserIPStatisticsViewSet(viewsets.ModelViewSet):
queryset = UserIPStatistics.objects.all()
serializer_class = UserIPStatisticsSerializer
permission_classes = (permissions.IsAuthenticated,)
4.配置路由
如果在应用中,需要将应用的路由包含到Project中urls中,这里假设读者具备这方面的基础知识。
router = routers.SimpleRouter()
router.register(r'useripstatistics', UserIPStatisticsViewSet)
urlpatterns += router.urls
urlpatterns = format_suffix_patterns(urlpatterns)
注意:模型数据一般放在models文件中,序列类可以放在views文件中,也可以放在单独的serializers文件中,数据视图类放在views文件中。
执行以下命令进行数据的迁移。
python.exe manage.py makemigrations
python.exe manage.py migrate
python.exe manage.py init
---------------------------------------------------------至此,后台配置完成-------------------------------------------------------
5.前端新建View组件
在src/views目标下新建UserIPStatistics文件夹,并新建api.js + crud.js +index.vue 三个文件。
api.js文件内容:
import { request } from '@/api/service' //系统封装好的请求后端数据
export const urlPrefix = '/colorlabel/useripstatistics/' //该组件访问的后端restful接口
/**
* 列表查询
*/
export function GetList (query) {
query.limit = 999
return request({
url: urlPrefix,
method: 'get',
params: query
})
}
/**
* 新增
*/
export function createObj (obj) {
return request({
url: urlPrefix,
method: 'post',
data: obj
})
}
/**
* 修改
*/
export function UpdateObj (obj) {
return request({
url: urlPrefix + obj.id + '/',
method: 'put',
data: obj
})
}
/**
* 删除
*/
export function DelObj (id) {
return request({
url: urlPrefix + id + '/',
method: 'delete',
data: { id }
})
}
crud.js文件内容:
主要是表格显示参数的配置。
// eslint-disable-next-line no-unused-vars
// import { request } from '@/api/service'
// eslint-disable-next-line no-unused-vars
// import { BUTTON_STATUS_NUMBER } from '@/config/button'
// eslint-disable-next-line no-unused-vars
// import { urlPrefix as bookPrefix } from './api'
export const crudOptions = (vm) => {
return {
pageOptions: {
compact: true
},
options: {
tableType: 'vxe-table',
rowKey: true, // 必须设置,true or false
rowId: 'id',
height: '100%', // 表格高度100%, 使用toolbar必须设置
highlightCurrentRow: false
},
rowHandle: {//操作按钮行的配置
width: 140,
view: {
thin: true,
text: '',
disabled () {
return !vm.hasPermissions('Retrieve')
}
},
edit: {
thin: true,
text: '',
disabled () {
return false
//return !vm.hasPermissions('Update')
},
show: false
},
remove: {
thin: true,
text: '',
hidden: true,
disabled () {
return false
//return !vm.hasPermissions('Delete')
},
show: false
}
},
indexRow: { // 或者直接传true,不显示title,不居中
title: '序号',
align: 'center',
width: 100
},
viewOptions: {
componentType: 'form'
},
formOptions: {
defaultSpan: 24, // 默认的表单 span
width: '35%'
},
columns: [{//每一列的字段指定
title: '关键词',
key: 'search',
show: false,
disabled: true,
search: {
disabled: false
},
form: {
disabled: true,
component: {
props: {
clearable: true
},
placeholder: '请输入关键词'
}
},
view: { // 查看对话框组件的单独配置
disabled: true
}
},
{
title: 'ID',
key: 'id',//与返回json数据的key对应
show: false,
disabled: true,
width: 90,
form: {
disabled: true
}
},
{
title: '用户名',
key: 'creator',
sortable: true,
treeNode: true,
search: {
disabled: false,
component: {
props: {
clearable: true
}
}
},
type: 'input',
form: {
editDisabled: true,
rules: [ // 表单校验规则
{ required: true, message: '编码必填项' }
],
component: {
props: {
clearable: true
},
placeholder: '请输入编码'
},
itemProps: {
class: { yxtInput: true }
}
}
},
{
title: 'IP',
key: 'ip',
sortable: true,
treeNode: true,
search: {
disabled: false,
component: {
props: {
clearable: true
}
}
},
type: 'input',
form: {
editDisabled: true,
rules: [ // 表单校验规则
{ required: true, message: '编码必填项' }
],
component: {
props: {
clearable: true
},
placeholder: '请输入编码'
},
itemProps: {
class: { yxtInput: true }
}
}
},
{
title: '次数',
key: 'num',
sortable: true,
search: {
disabled: false,
component: {
props: {
clearable: true
}
}
},
type: 'number',
form: {
rules: [ // 表单校验规则
{ required: true, message: '显示值必填项' }
],
component: {
props: {
clearable: true
},
placeholder: '请输入显示值'
},
itemProps: {
class: { yxtInput: true }
}
}
}
]//.concat(vm.commonEndColumns())
}
}
index.vue 文件内容:
<template>
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners">
<div slot="header">
<crud-search ref="search" :options="crud.searchOptions" @submit="handleSearch" />
<crud-toolbar :search.sync="crud.searchOptions.show" :compact.sync="crud.pageOptions.compact" :columns="crud.columns" @refresh="doRefresh()" @columns-filter-changed="handleColumnsFilterChanged"/>
</div>
</d2-crud-x>
</d2-container>
</template>
<script>
import * as api from './api'
import { crudOptions } from './crud'
import { d2CrudPlus } from 'd2-crud-plus'
export default {
name: 'useripstatistics',
mixins: [d2CrudPlus.crud],
data () {
return {}
},
methods: {
getCrudOptions () {
return crudOptions(this)
},
pageRequest (query) {
return api.GetList(query)
},
/*addRequest (row) {
d2CrudPlus.util.dict.clear()
return api.createObj(row)
},
updateRequest (row) {
d2CrudPlus.util.dict.clear()
return api.UpdateObj(row)
},
delRequest (row) {
return api.DelObj(row.id)
},*/
// 授权
createPermission (scope) {
this.$router.push({
name: 'menuButton',
params: { id: scope.row.id },
query: { name: scope.row.name }
})
}
}
}
</script>
<style lang="scss">
.yxtInput {
.el-form-item__label {
color: #49a1ff;
}
}
</style>
注意如果是上传文件,应该使用file-uploader类型。并在valueResolve (row, key) 方法中修改值为文件名,否则报错。
valueBuilder (row, key)//在返回之后,填入界面之前进行
{
// 某些组件传入的value值可能是一个复杂对象,而row中的单个属性的值不合适传入
// 则需要在打开编辑对话框前将row里面多个字段组合成组件需要的value对象
// 例如:国际手机号(mobileValue为此column的key)
// 示例 http://preview.d2-crud-plus.docmirror.cn/D2CrudPlusExample/#/demo/form/phone
// row.mobileValue = { phoneNumber: row.phone, callingCode: row.code, countryCode: row.country }
// valueBuilder将会在pageRequest成功返回数据后执行
},
valueResolve (row, key)//在上传序列化之前进行
{
// 组件中传回的值也需要分解成row中多个字段的值,用于提交给后台。
// 例如:
// if (row.mobileValue != null) {
// row.phone = row.mobileValue.phoneNumber
// row.code = row.mobileValue.callingCode
// row.country = row.mobileValue.countryCode
// }
// valueResolve 将会在
// addRequest(解析添加表单的值)
// updateRequest(解析编辑表单的值)
// pageRequest(解析查询参数)
// 之前执行
}
6.配置后台
添加菜单,配置如下,需要改成自己的配置。
配置访问方式
点击按钮配置,按restful api方式添加增删查改的路由路径。
刷新以下后台,菜单界面就是显示出来最终结果:
7.总结
dvadmin 能够以简易快捷的方式构建一套后台管理系统,能够快速进行后台表格的管理,十分友好便捷,缺点就是文档,不是很全面,遇到bug需要自己诊断一下源码,找出问题所在。