# 快速开发CRUD

本页面示例中的 `project` 均为demo名,可替代成自己的项目名

# 需求

  • 创建一个项目管理app;
  • 字段包含:项目名称、项目编码、项目负责人;
  • 功能:包含项目管理的增删改查、导出。

# 后端

# 1. 创建App

  • 通过命令创建App python3 manage.py createapp project

# 2. 创建 models 模型

    1. dvadmin-backend/apps/project/models/ 目录下,创建 project.py 文件(models目录下可创建多个模型文件,建议一个.py 文件为一个models模型)
    1. 编写项目管理模型内容 dvadmin-backend/apps/project/models/project.py,如下:
from django.conf import settings
from django.db.models import CharField, ForeignKey, CASCADE, SET_NULL

from vadmin.op_drf.models import CoreModel


# 继承框架封装的 模型类 CoreModel
class Project(CoreModel):
    name = CharField(max_length=8, verbose_name='项目名称')
    code = CharField(max_length=8, verbose_name='项目编码')
    # 在关联用户时,建议使用 to=settings.AUTH_USER_MODEL 进行关联
    person = ForeignKey(to=settings.AUTH_USER_MODEL, null=True, verbose_name='项目负责人', related_name='project_person',
                        on_delete=SET_NULL, db_constraint=False)
    # 在普通一多一、一对多、多对多时,to='App名.模块名' 进行关联
    dept = ForeignKey(to='permission.dept', on_delete=CASCADE, verbose_name="项目所属部门", related_name='project_dept',
                      db_constraint=False)

    class Meta:
        verbose_name = '项目管理'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f"{self.name} 项目"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    1. dvadmin-backend/apps/project/models/__init__.py 中导入模型
from .project import Project
1

# 3. 迁移数据库文件

  • 执行迁移命令:
    • python3 manage.py makemigrations project
    • python3 manage.py migrate project
  • 迁移成功后,通过数据库可查看到
  • 可看到字段比模型中多出几个,是因为继承了框架封装的 CoreModel 所带的。

# 4. 创建过滤器、序列化器、视图、路由接口

    1. 创建过滤器,通过 dvadmin-backend/apps/project/filters.py 文件中,添加过滤器内容:
import django_filters

from .models import Project


class ProjectFilter(django_filters.rest_framework.FilterSet):
    """
    项目管理 简单序过滤器
    """
    # 通过 lookup_expr 可进行模糊查询,其他配置可自行百度
    name = django_filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = Project
        exclude = ('description', 'creator', 'modifier')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 2) 创建序列化器
from rest_framework import serializers

from project.models import Project
from vadmin.op_drf.serializers import CustomModelSerializer


# ================================================= #
# ************** 项目管理 序列化器  ************** #
# ================================================= #
class ProjectSerializer(CustomModelSerializer):
    """
    项目管理 简单序列化器
    """

    class Meta:
        model = Project
        fields = '__all__'


class ProjectCreateUpdateSerializer(CustomModelSerializer):
    """
    项目管理 创建/更新时的列化器
    """

    # 此处可写定制的 创建/更新 内容
    def validate(self, attrs: dict):
        return super().validate(attrs)

    class Meta:
        model = Project
        fields = '__all__'


class ExportProjectSerializer(CustomModelSerializer):
    """
    导出 项目管理 简单序列化器
    """
    person__username = serializers.SerializerMethodField(read_only=False)
    dept__deptName = serializers.SerializerMethodField(read_only=False)

    def get_person__username(self, obj):
        return "" if not hasattr(obj, 'person') else obj.person.username

    def get_dept__deptName(self, obj):
        return "" if not hasattr(obj, 'dept') else obj.dept.deptName

    class Meta:
        model = Project
        fields = ('id', 'name', 'code', 'person', 'person__username', 'dept', 'dept__deptName', 'creator', 'modifier',
                  'description')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    1. 创建视图
from project.filters import ProjectFilter
from project.models import Project
from project.serializers import ProjectSerializer, ProjectCreateUpdateSerializer, ExportProjectSerializer
from apps.vadmin.op_drf.filters import DataLevelPermissionsFilter
from apps.vadmin.op_drf.viewsets import CustomModelViewSet
from apps.vadmin.permission.permissions import CommonPermission


class ProjectModelViewSet(CustomModelViewSet):
    """
    项目管理 的CRUD视图
    """
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer  # 序列化器
    create_serializer_class = ProjectCreateUpdateSerializer  # 创建/更新时的列化器
    update_serializer_class = ProjectCreateUpdateSerializer  # 创建/更新时的列化器
    filter_class = ProjectFilter  # 过滤器
    extra_filter_backends = [DataLevelPermissionsFilter]  # 数据权限类,不需要可注释掉
    update_extra_permission_classes = (CommonPermission,)  # 判断用户是否有这条数据的权限
    destroy_extra_permission_classes = (CommonPermission,)  # 判断用户是否有这条数据的权限
    create_extra_permission_classes = (CommonPermission,)  # 判断用户是否有这条数据的权限
    search_fields = ('name',)  # 搜索
    ordering = ['create_datetime']  # 默认排序
    # 导出
    export_field_data = ['项目序号', '项目名称', '项目编码', '项目负责人', '项目所属部门', '创建者', '修改者', '备注']  # 导出
    export_serializer_class = ExportProjectSerializer  # 导出序列化器
    # 导入
    import_field_data = {'name': '项目名称', 'code': '项目编码', 'person': '项目负责人ID', 'dept': '部门ID'}
    import_serializer_class = ExportProjectSerializer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    1. 创建路由接口
from django.urls import re_path
from rest_framework.routers import DefaultRouter

from project.views import ProjectModelViewSet

router = DefaultRouter()
router.register(r'project', ProjectModelViewSet)

urlpatterns = [
    # 导出项目
    re_path('project/export/', ProjectModelViewSet.as_view({'get': 'export', })),
    # 项目导入模板下载及导入
    re_path('project/importTemplate/',
            ProjectModelViewSet.as_view({'get': 'importTemplate', 'post': 'importTemplate'})),
]

urlpatterns += router.urls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 前端

# 1. 创建 .vue 文件和 api 文件

  • 在目录dvadmin-ui/src/api/project/下创建project.js

代码如下:

import request from '@/utils/request'

// 查询项目列表
export function listProject(query) {
  return request({
    url: '/project/project/',
    method: 'get',
    params: query
  })
}

// 查询项目详细
export function getProject(projectId) {
  return request({
    url: '/project/project/' + projectId + '/',
    method: 'get'
  })
}

// 新增项目
export function addProject(data) {
  return request({
    url: '/project/project/',
    method: 'post',
    data: data
  })
}

// 修改项目
export function updateProject(data) {
  return request({
    url: '/project/project/' + data.id + '/',
    method: 'put',
    data: data
  })
}

// 删除项目
export function delProject(projectId) {
  return request({
    url: '/project/project/' + projectId + '/',
    method: 'delete'
  })
}

// 导出项目
export function exportProject(query) {
  return request({
    url: '/project/project/export/',
    method: 'get',
    params: query
  })
}

// 下载项目导入模板
export function importTemplate() {
  return request({
    url: '/project/project/importTemplate/',
    method: 'get'
  })
}

// 项目导入
export function importsProject(data) {
  return request({
    url: '/project/project/importTemplate/',
    method: 'post',
    data: data
  })
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  • 在目录dvadmin-ui/src/views/project/project/下创建index.vue( 第一个 project 目录类似后端app,第二个 project目录类似后端视图,好处:结构会清晰化),内容如下:

# 2. 添加菜单

  • 在前端系统中,权限管理 ———— 菜单管理 ———— 添加菜单
  • 添加 项目管理侧边栏
  • 添加 项目 二级末级菜单
  • 添加 增、删、改、查、导入、导出按钮
  • 最终添加完成后如下:
  • 刷新后即可看到左侧菜单

# 3. vue 中实现增、删、改、查、导入、导出

<template>
  <div>
    <model-display :listApi="listApi" :fields="fields" :funcs="funcs"></model-display>
  </div>
</template>

<script>
  import * as Project from '../../../api/project/project';

  export default {
    name: "project",
    data() {
      return {
        listApi: Project.listProject,
        fields: [
          {prop: 'id', label: 'ID', show: false, unique: true, required: false},
          {prop: 'name', label: '项目名称', show: true, search: true, form: true, required: true,},
          {prop: 'code', label: '项目编码', show: true, search: true, form: true, required: true,},
          {prop: 'person', label: '项目负责人', show: true, search: true, sortable: true, type: 'users', form:true,required: true,},
          {prop: 'dept', label: '部门', show: true, search: true, type: 'depts', form:true,required: true},
          {prop: 'create_datetime', label: '创建时间', show: true, search: true, type: 'date'},
          {prop: 'creator_name', label: '创建者', show: true, search: false},
          {prop: 'description', label: '描述', show: true, search: false, form:true}
        ],
        funcs: [
          {type: 'add', label: '新增', permis: ['project:project:post'], 'icon': 'el-icon-plus', api:Project.addProject},
          {type: 'update', label: '修改', permis: ['project:project:{id}:put'], api: Project.updateProject},
          {type: 'delete', label: '删除', permis: ['project:project:{id}:delete'], api: Project.delProject},
          {type: 'export', label: '导出', permis: ['project:project:export:get'], api: Project.exportProject},
          {type: 'import', label: '导入', permis: ['project:project:importTemplate:get','project:project:importTemplate:post'], api: Project.importsProject, template_api:Project.importTemplate},
          {type: 'select', label: '详情', permis: ['project:project:get'], api: Project.getProject},
        ],
      }
    },
    created() {
    },
    mounted() {
    },
    methods: {
    }

  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 完成

  • 刷新页面打开 项目管理——项目,则是一个简单完整的 CRUD 完成。
  • 如有问题可参考:https://gitee.com/liqianglog/django-vue-admin/tree/demo_project 分支代码。