文章目录
- 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_nameordering = ('-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 = UserIPStatisticsfields = '__all__'read_only_fields = ('id', 'zl_user')
3.新建数据视图
指明查询集,序列化类和权限验证类。与文章开始的图保持一致。
# IP统计数据
class UserIPStatisticsViewSet(viewsets.ModelViewSet):queryset = UserIPStatistics.objects.all()serializer_class = UserIPStatisticsSerializerpermission_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 = 999return 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 falserowId: '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, // 默认的表单 spanwidth: '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需要自己诊断一下源码,找出问题所在。