8.用户管理专栏主页面开发
用户管理专栏主页面开发
- 写在前面
- 用户权限控制
- 用户列表接口设计
- 主页面开发
- 前端
- account/Index.vue
- langs/zh.js
- store.js
- 后端
- Paginator
- 概述
- 基本用法
- 代码示例
- 属性与方法
- urls.py
- views.py
- 运行效果
- 总结
欢迎加入Gerapy二次开发教程专栏!
本专栏专为新手开发者精心策划了一系列内容,旨在引领你深入探索Gerapy框架的二次迭代之旅。
本专栏将全面剖析Gerapy与Vue的源码架构,让你从内部了解它们的运作机制。
我们将分享实用的技巧,教你如何有效修复Gerapy中的异常问题,如何在现有基础上添加多样化的功能,以及如何对已有功能进行重构优化。
写在前面
读完本篇博客你可以学习到的知识:
- 如何进行用户权限控制
- 如何设计列表页(翻页)接口
- 加深前后端开发经验,利用Django Paginator实现翻页请求
用户权限控制
一般情况下,超级管理员只会有一两个,我们想在前端知道登录用户的身份的话,必须要后端提供对应标识,但是现在已知的接口和缓存都没有存储用户身份标识,那么就需要我们重新开发提供了。
再来看下auth_user表,is_superuser就是用来标识超级管理员身份

这里就有两个方案了:
- 单独开一个接口获取当前登录用户身份
- 由于刚好是操作
auth_user表用到,可以在拿auth_user表数据时顺便计算返回
这里看大家自己的选择,下面我用的是第二个方案,也就是每次请求列表页时,会返回is_superuser字段标识用户身份。
用户列表接口设计
- 接口:
/api/account/list?pageSize=10¤tPage=1 - 请求:
GET - 页数参数:
pageSize,页码参数:currentPage - 响应接口字段:

主页面开发
这是后续我们需要用到的四个文件的作用,Status.vue不需要用到,删除即可

前端
account/Index.vue
下面是全部代码,有些注释,具体的大家得自己熟悉熟悉,没法仔细讲,不过流程是清晰的。
<template><div class="panel"><panel-title :title="$lang.objects.accounts"><!--新增按钮实现--><router-link :to="{ name: 'accountCreate' }" tag="span"><el-button size="mini" type="success"><i class="fa fa-plus"></i>{{ $lang.buttons.create }}</el-button></router-link></panel-title><div class="panel-body"><!--遍历accounts--><el-tablev-loading="loading":data="accounts":element-loading-text="$lang.messages.loading":empty-text="$lang.messages.noData":style="{ width: '100%;' }"><!--各字段呈现实现--><el-table-column:label="$lang.columns.username"align="center"prop="username"min-width="30%"></el-table-column><el-table-column:label="$lang.columns.email"align="center"prop="email"min-width="30%"></el-table-column><el-table-column :label="$lang.columns.is_superuser" align="center" min-width="30%"><template slot-scope="props"><span v-if="props.row.is_superuser"><el-button icon="el-icon-check" round size="mini" type="primary"></el-button></span><span v-else><el-button icon="el-icon-close" round size="mini" type="primary"></el-button></span></template></el-table-column><el-table-column :label="$lang.columns.is_staff" align="center" min-width="30%"><template slot-scope="props"><span v-if="props.row.is_staff"><el-button icon="el-icon-check" round size="mini" type="primary"></el-button></span><span v-else><el-button icon="el-icon-close" round size="mini" type="primary"></el-button></span></template></el-table-column><el-table-column :label="$lang.columns.is_active" align="center" min-width="30%"><template slot-scope="props"><span v-if="props.row.is_active"><el-button icon="el-icon-check" round size="mini" type="primary"></el-button></span><span v-else><el-button icon="el-icon-close" round size="mini" type="primary"></el-button></span></template></el-table-column><el-table-column:label="$lang.columns.date_joined"align="center"prop="date_joined"min-width="30%"></el-table-column><el-table-column:label="$lang.columns.last_login"align="center"prop="last_login"min-width="30%"></el-table-column><!--isSupperUserLogin标识超级管理员身份--><el-table-column v-if="isSupperUserLogin" :label="$lang.columns.operations" align="center" min-width="50%"><template slot-scope="props"><router-link :to="{ name: 'accountEdit', params: { id: props.row.id } }" tag="span"><!--指定列跳转编辑页--><el-button size="mini" type="info"><i class="fa fa-edit"></i>{{ $lang.buttons.edit }}</el-button></router-link><!--指定列删除--><el-button size="mini" type="danger" @click="onSingleDelete(props.row.id)"><i class="fa fa-remove"></i>{{ $lang.buttons.delete }}</el-button></template></el-table-column></el-table></div></div>
</template>
<script type="text/javascript">
import PanelTitle from "../../components/PanelTitle";export default {data() {return {accounts: [], // 用户数据列表loading: true, // 加载中isSupperUserLogin: true, // 是否是超级管理员身份totalCount: 0, // 用户数据总数currentPage: 1, // 当前页码pageSize: 10, // 页数};},components: {PanelTitle,},created() {// 页面创建时请求数据this.getAccountData(this.currentPage, this.pageSize);},methods: {// 请求用户数据getAccountData(current_page, page_size) {this.loading = true;// GET传参方式this.$http.get(this.$store.state.url.account.list, {'params': {pageSize: page_size,currentPage: current_page,}}).then(({data: data}) => {this.accounts = data['rows'];this.totalCount = data['count'];this.isSupperUserLogin = data['is_superuser'];this.loading = false;}).catch(() => {this.loading = false;});},// 删除指定用户deleteAccount(id) {this.$http.post(this.formatString(this.$store.state.url.account.remove, {id: id,})).then(() => {this.$message.success(this.$store.getters.$lang.messages.successDelete);this.loading = false;this.getAccountData(this.currentPage, this.pageSize);}).catch(() => {this.$message.error(this.$store.getters.$lang.messages.errorDelete);this.loading = false;});},// 提交删除用户onSingleDelete(id) {this.$confirm(this.$store.getters.$lang.messages.confirm,this.$store.getters.$lang.buttons.confirm,{confirmButtonText: this.$store.getters.$lang.buttons.yes,cancelButtonText: this.$store.getters.$lang.buttons.no,type: "warning",}).then(() => {this.deleteAccount(id);});},},
};
</script>
langs/zh.js
需要在columns下增加些配置参数

is_superuser: '超级用户',
is_staff: '工作人员',
is_active: '状态',
date_joined: '加入时间',
last_login: '最后登录时间',
deployed_user_name: '部署者',
deployed_client_name: '部署主机',
deployed_project_name: '部署项目',
deployed_description: '部署描述',
deployed_at: '部署时间',
priority: '优先级',
store.js
需要在url下增加些配置参数


account: {list: "/api/account/list",create: "/api/account/create",info: "/api/account/{id}/info",update: "/api/account/{id}/update",remove: "/api/account/{id}/remove",
},
后端
Paginator
这里我们先了解一下Django的翻页器Paginator
概述
Django的Paginator是一个内置的分页组件,用于将大量数据分页显示,从而改善用户体验并减轻服务器压力。使用Paginator可以指定每页显示的数据项数量,并生成一个分页对象,该对象包含了关于总页数、当前页码等信息的方法。
基本用法
引入Paginator类:首先需要从django.core.paginator模块中引入Paginator类。
创建Paginator对象:使用Paginator(object_list, per_page)创建一个分页器对象,其中object_list是要分页的数据列表,per_page是每页显示的数据条数。
获取页面数据:通过调用分页器对象的page(page_number)方法获取特定页面的数据,其中page_number是页码。返回的是一个Page对象,该对象提供了当前页的数据项列表以及其他分页信息,如是否有下一页、上一页等。
代码示例
from django.core.paginator import Paginator# 假设有一个包含100条数据的列表
objects = ['item1', 'item2', ..., 'item100']
# 创建Paginator对象,每页显示10条数据
paginator = Paginator(objects, 10)# 获取第一页的数据
page1 = paginator.page(1)
print(page1.object_list) # 输出当前页的数据项列表
print(page1.has_next()) # 检查是否有下一页
print(page1.has_previous()) # 检查是否有上一页
print(page1.number) # 当前页码
属性与方法
paginator.count: 总数据项数paginator.num_pages: 总页数paginator.page_range: 一个范围对象,包含所有页码page.object_list: 当前页的数据项列表page.number: 当前页码page.has_next(): 是否有下一页page.has_previous(): 是否有上一页page.next_page_number(): 下一页的页码(如果有的话)page.previous_page_number(): 上一页的页码(如果有的话)
urls.py
新增两个接口映射
url(r'^api/account/list', views.account_list, name='account_list'),
url(r'^api/account/(\d+)/remove', views.account_remove, name='account_remove'),
views.py
导入需要的包
from django.contrib.auth.models import User
from django.core.paginator import Paginator
方法代码开发,具体实现代码有注释
@log_exception()
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def account_list(request):"""account list:param request: request object:return: json"""if request.method == 'GET':# 获取单页页数page_size = int(request.query_params.get('pageSize'))# 拿到当前页current_page = int(request.query_params.get('currentPage'))# 根据主键id顺序排序拿到全部数据对象accounts = User.objects.order_by('id')# 创建翻页器Paginator对象,全部数据 单页页数paginator = Paginator(accounts, page_size)# 提取指定页码的数据page_obj = paginator.get_page(current_page)# model_to_dict:模型数据转字典,定义导出的字段fields = ['id', 'username', 'email', 'is_superuser', 'date_joined', 'last_login', 'is_staff', 'is_active']# 最后拼接数据返回return JsonResponse({'currentPage': current_page, 'pageSize': page_size, 'count': paginator.count,'num_pages': paginator.num_pages, 'is_superuser': request.user.is_superuser,'rows': [model_to_dict(item, fields=fields) for item in page_obj.object_list]})@log_exception()
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def account_remove(request, account_id):"""remove account by account_id:param request: request object:param account_id: account id:return: json"""if request.method == 'POST':# 根据用户id查询并删除User.objects.filter(id=account_id).delete()return JsonResponse({'result': '1'})
运行效果
处理好后,打包Vue代码,重新启动后端服务,刷新浏览器。

这里留个坑给大家自己实现,就是删除按钮应该给超级管理员隐藏或者不可用,毕竟他要是删了自己账号还管理个啥!
总结
到这里,我们就实现了主页面开发了,接下来将实现其他页面~
相关文章:
8.用户管理专栏主页面开发
用户管理专栏主页面开发 写在前面用户权限控制用户列表接口设计主页面开发前端account/Index.vuelangs/zh.jsstore.js 后端Paginator概述基本用法代码示例属性与方法 urls.pyviews.py 运行效果 总结 欢迎加入Gerapy二次开发教程专栏! 本专栏专为新手开发者精心策划了…...
室内指路机器人是否支持与第三方软件对接?
嘿,你知道吗?叁仟室内指路机器人可有个超厉害的技能,那就是能和第三方软件 “手牵手” 哦,接下来就带你一探究竟! 从技术魔法角度看哈:好多室内指路机器人都像拥有超能力的小魔法师,采用开放式…...
Apache BookKeeper Ledger 的底层存储机制解析
Apache BookKeeper 的 ledger(账本)是其核心数据存储单元,底层存储机制结合了日志追加(append-only)、分布式存储和容错设计。Ledger 的数据存储在 Bookie 节点的磁盘上,具体实现涉及 Journal(日…...
从代码上深入学习GraphRag
网上关于该算法的解析都停留在大概流程上,但是具体解析细节未知,由于代码是PipeLine形式因此阅读起来比较麻烦,本文希望通过阅读项目代码来解析其算法的具体实现细节,特别是如何利用大模型来完成图谱生成和检索增强的实现细节。 …...
通俗地讲述DDD的设计
通俗地讲述DDD的设计 前言为什么要使用DDDDDD架构分层重构实践关键问题解决方案通过领域事件机制解耦服务依赖:防止逻辑下沉 领域划分电商场景下的领域划分 结语完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,…...
【Redis】通用命令
使用者通过redis-cli客户端和redis服务器交互,涉及到很多的redis命令,redis的命令非常多,我们需要多练习常用的命令,以及学会使用redis的文档。 一、get和set命令(最核心的命令) Redis中最核心的两个命令&…...
网络安全技术文档
网络安全技术文档 1. 概述 网络安全是指通过技术手段和管理措施,保护网络系统的硬件、软件及其数据不受偶然或恶意破坏、更改、泄露,确保系统连续可靠运行,网络服务不中断。 2. 常见网络威胁 2.1 攻击类型 DDoS攻击:分布式拒…...
微前端随笔
✨ single-spa: js-entry 通过es-module 或 umd 动态插入 js 脚本 ,在主应用中发送请求,来获取子应用的包, 该子应用的包 singleSpa.registerApplication({name: app1,app: () > import(http://localhost:8080/app1.js),active…...
【36期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深A股当天逐笔大单交易数据及接口API说明文档
在量化分析领域,实时且准确的数据接口是成功的基石。经过多次实际测试,我将已确认可用的数据接口分享给正在从事量化分析的朋友们,希望能够对你们的研究和工作有所帮助,接下来我会用Python、JavaScript(Node.js&…...
C++中的浅拷贝和深拷贝
浅拷贝只是将变量的值赋予给另外一个变量,在遇到指针类型时,浅拷贝只会把当前指针的值,也就是该指针指向的地址赋予给另外一个指针,二者指向相同的地址; 深拷贝在遇到指针类型时,会先将当前指针指向地址包…...
二叉树与红黑树核心知识点及面试重点
二叉树与红黑树核心知识点及面试重点 一、二叉树 (Binary Tree) 1. 基础概念 定义:每个节点最多有两个子节点(左子节点和右子节点) 术语: 根节点:最顶层的节点 叶子节点:没有子节点的节点 深度…...
GitHub 趋势日报 (2025年04月01日)
GitHub 趋势日报 (2025年04月01日) 本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星语言1punkpeye/awesome-mcp-serversA collection of MCP servers.⭐ 3280未指定2th-ch/youtube-musicYouTu…...
Java的SeleniumChromeDriver的常用方法
启动和关闭浏览器: driver.get(url):打开指定的URL。driver.quit():关闭浏览器并结束ChromeDriver会话。 元素定位: driver.findElement(By.id("elementId")):通过元素的ID定位。driver.findElement(By.cl…...
字符串、列表、元组、字典
字符串 双引号或者单引号中的数据,就是字符串 字符串输入 之前在学习input的时候,通过它能够完成从键盘获取数据,然后保存到指定的变量中; 注意:input获取的数据,都以字符串的方式进行保存,即…...
【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60‘ did not match any bands”
【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 文章目录 【GEE学习笔记】报错解决:“Image.selec…...
AI可以赋能的三农产品、机械与服务
三农赛道涵盖农业、农村和农民相关的产品与服务,涉及农资、农业机械、智能设备、农产品加工及数字化服务等多个领域。随着人工智能(AI)技术的飞速发展,AI正在通过赋能农业的生产、管理、销售等各个环节,推动传统农业向…...
ngx_timezone_update
定义在 src\os\unix\ngx_time.c void ngx_timezone_update(void) { #if (NGX_FREEBSD)if (getenv("TZ")) {return;}putenv("TZUTC");tzset();unsetenv("TZ");tzset();#elif (NGX_LINUX)time_t s;struct tm *t;char buf[4];s tim…...
车载诊断架构 --- 整车重启先后顺序带来的思考
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...
GESP C++三级 知识点讲解
C编程三级标准 (一)知识点详述 (1)了解二进制数据编码:原码、反码、补码。 (2)掌握数据的进制转换:二进制、八进制、十进制、十六进制。 (3)掌握位运算:与(&)、或(|)、非(~)、异或(^)、左移(<<)、右移(>>)的基本使用方法及原理。 (4)了解算法的概念与描述&…...
前端 vs 后端:技术分工详解——从用户界面到系统逻辑的全解析
前端(Frontend) 和 后端(Backend) 是软件开发中两个核心概念,分别对应用户直接交互的部分和系统背后的逻辑处理部分。它们共同构成完整的应用程序,但分工不同。 目录 一、前端(Frontend…...
Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结
以下是 Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结: 1. Redis 事务(Transactions) 功能描述 事务通过 MULTI 和 EXEC 命令将一组命令打包执行,保证…...
JavaScript智能对话机器人——企业知识库自动化
引言 内部知识管理常面临信息分散、查找困难的问题。本文将使用Node.js和虎跃办公的智能对话API,构建企业级知识问答机器人,支持自然语言查询和自动学习。 核心技术 自然语言处理(NLP)意图识别机器学习模型微调REST API集成 代…...
JS实现AES和DES
目录 目标 概述 DES AES 实战 JS实现DES JS实现AES 目标 了解AES和DES的特点并用JS实现。 概述 DES 翻译过来叫数据加密标准。它有5种加密模式(CTR、OFB、CFB、CBC、ECB),在JS中,不同加密模式语法结构几乎一致,…...
【C++11(下)】—— 我与C++的不解之缘(三十二)
前言 随着 C11 的引入,现代 C 语言在语法层面上变得更加灵活、简洁。其中最受欢迎的新特性之一就是 lambda 表达式(Lambda Expression),它让我们可以在函数内部直接定义匿名函数。配合 std::function 包装器 使用,可以…...
Windows 10/11系统优化工具
家庭或工作电脑使用时间久了,会出现各种各样问题,今天给大家推荐一款专为Windows 10/11系统设计的全能优化工具,该软件集成了超过40项专业级实用程序,可针对系统性能进行深度优化、精准调校、全面清理、加速响应及故障修复。通过系…...
浅谈在HTTP中GET与POST的区别
从 HTTP 报文来看: GET请求方式将请求信息放在 URL 后面,请求信息和 URL 之间以 ?隔开,请求信息的格式为键值对,这种请求方式将请求信息直接暴露在 URL 中,安全性比较低。另外从报文结构上来看,…...
LightRAG实战:轻松构建知识图谱,破解传统RAG多跳推理难题
作者:后端小肥肠 🍊 有疑问可私信或评论区联系我。 🥑 创作不易未经允许严禁转载。 姊妹篇: 2025防失业预警:不会用DeepSeek-RAG建知识库的人正在被淘汰_deepseek-embedding-CSDN博客 从PDF到精准答案:Coze…...
C++多线程编码二
1.lock和try_lock lock是一个函数模板,可以支持多个锁对象同时锁定同一个,如果其中一个锁对象没有锁住,lock函数会把已经锁定的对象解锁并进入阻塞,直到多个锁锁定一个对象。 try_lock也是一个函数模板,尝试对多个锁…...
垃圾回收——三色标记法(golang使用)
三色标记法(tricolor mark-and-sweep algorithm)是传统 Mark-Sweep 的一个改进,它是一个并发的 GC 算法,在Golang中被用作垃圾回收的算法,但是也会有一个缺陷,可能程序中的垃圾产生的速度会大于垃圾收集的速度,这样会导…...
Linux学习笔记——零基础详解:什么是Bootloader?U-Boot启动流程全解析!
零基础详解:什么是Bootloader?U-Boot启动流程全解析! 一、什么是Bootloader?📌 举个例子: 二、U-Boot 是什么?三、U-Boot启动过程:分为两个阶段🔹 第一阶段(汇…...
