用戶管理專欄主頁面開發
- 寫在前面
- 用戶權限控制
- 用戶列表接口設計
- 主頁面開發
- 前端
- 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代碼,重新啟動后端服務,刷新瀏覽器。
這里留個坑給大家自己實現,就是刪除按鈕應該給超級管理員隱藏或者不可用
,畢竟他要是刪了自己賬號還管理個啥!
總結
到這里,我們就實現了主頁面開發了,接下來將實現其他頁面~