利用Django和自带的Admin后台快速开发手机管理系统

项目背景

公司内部测试使用的手机历史不是很多,没有专门纳管。后面随着规模变大,测试手机也越来越多,测试、开发、设计等人员都会借用。时间长了不确定手机都在谁的手里,不方便管理。

测试提出需求,需要有个简单的小系统能进行手机统一管理。

需求有

1、管理员可以进行手机录入、修改、删除、查询等功能。

2、除了手机管理里面,测试、开发、设计等人员可以查看手机列表手机借用列表 以及申请手机 三个核心功能

3、测试、开发、设计等人员申请手机之后,自动发送消息(邮件)给管理员。然后找管理员认领手机

4、手机使用完毕归还时,先交还手机给 管理员,然后管理员修改 ”手机借用列表“ 中的对应记录的 ”归还时间“

设计思路

1、定义 Phone 和 BorrowRecord 两个模型

2、利用Django自带的后台快速实现

3、在Django后台自定义action,进行”手机申请“

4、申请按钮点击之后,同步给管理员发送消息(邮箱、钉钉)

进入开发

1、模型定义

这里除了手机序列号,还添加了 手机品牌和手机型号两个属性,便于后续扩展。

另外时间上设计了 采购时间、入库时间和报废时间三个属性。

手机的状态有 空闲中、被借走、已故障三种,当然你可以结合自己实际的情况设置其他状态。

# cmdb/models/phone.py
from django.db import models
from django.contrib.auth import get_user_model


User = get_user_model()


class Phone(models.Model):
    STATUS = (
        ('空闲中', '空闲中'),
        ('被借走', '被借走'),
        ('已故障', '已故障')
    )
    brand = models.CharField(max_length=32, unique=True, verbose_name='手机品牌')
    model = models.CharField(max_length=32, verbose_name='手机型号')
    serial_number = models.CharField(max_length=64, unique=True, verbose_name='手机序列号')
    create_time = models.DateTimeField(auto_now=True, verbose_name='入库时间')
    buy_time = models.DateField(null=True, blank=True, verbose_name='采购时间')
    fault_time = models.DateField(null=True, blank=True, verbose_name='故障时间')
    status = models.CharField(max_length=12, choices=STATUS, default='空闲中', verbose_name='手机状态')

    def __str__(self) -> str:
        return f'{self.model}/{self.serial_number}'
    
    class Meta:
        verbose_name = '测试手机管理'
        verbose_name_plural = verbose_name


class BorrowRecord(models.Model):
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='手机借用人')
    phone = models.ForeignKey(Phone, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='借用的手机')
    borrow_date = models.DateTimeField(auto_now_add=True, verbose_name='借用时间')
    return_date = models.DateTimeField(null=True, blank=True, verbose_name='归还时间')

    def __str__(self) -> str:
        return f'{self.user.get_username}/{self.phone.model}'
    
    class Meta:
        verbose_name = '手机借用/归还记录'
        verbose_name_plural = verbose_name

2、进行配置和绑定应用

# 配置可访问主机IP
ALLOWED_HOSTS = ['127.0.0.1']

# 绑定应用到项目
INSTALLED_APPS = [
    ... ...
    'cmdb'
]

# 设置 templates 根目录
# 默认会从 appname/templates/appname 目录寻找 ('APP_DIRS': True 参数决定)
TEMPLATES = [
    ... ...
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
    ... ...
]

这里是项目演示,所以数据库使用默认的 Sqlite 数据库即可

3、后台的自定义

因为是借助于Django自带后台快速开发一个简易版手机管理系统,所有手机的管理和用户的借用都是在 Django默认后台实现的。

默认创建模型之后,在应用的 admin.py中进行绑定,然后就可以通过 自带的后台进行模型的管理,比如这里的 手机和手机借用记录的管理。

但是默认是没有”申请借用“的功能的,这个就需要我们开发对应的功能,并且添加到Django Admin后台去。

核心知识: 通过继承admin.ModelAdmin来实现自定义 模型的ModelAdmin 行为 (展示、搜索、排序、方法等)

这里先给出代码,然后进行代码分析

# cmdb/admin.py
from django.contrib import admin, messages
from cmdb.models import BorrowRecord, Phone
from django.http import HttpResponseRedirect
from django.urls import reverse


class PhoneAdmin(admin.ModelAdmin):
    list_display = ('brand', 'model', 'serial_number', 'fault_time', 'create_time', 'status', 'fault_time')
    list_filter = ('brand', 'status')
    search_fields = ('status', 'model', 'serial_number')
    actions = ['apply_for_borrow']
    def apply_for_borrow(self, request, queryset):
        if len(queryset) > 1:
            self.message_user(request, '抱歉,每次只能申请一台手机', level=messages.ERROR)
        else:
            if queryset[0].status != '空闲中':
                self.message_user(request, '抱歉,不能选择已故障或者被借走的手机', level=messages.ERROR)
            else:
                obj = queryset[0]
                next_url = '/admin/cmdb/phone/'
                base_url = reverse('cmdb:borrow-phone', kwargs={'pk': obj.id})
                borrow_url = f'{base_url}?next={next_url}'
                return HttpResponseRedirect(borrow_url)
    apply_for_borrow.short_description = '申请借用'


class BorrowRecordAdmin(admin.ModelAdmin):
    list_display = ('phone', 'user', 'borrow_date', 'return_date')
        
# Register your models here.
admin.site.register(Phone, PhoneAdmin)
admin.site.register(BorrowRecord, BorrowRecordAdmin)

上面定义了 PhoneAdmin 和 BorrowRecordAdmin 两个ModelAdmin类,然后通过 admin.site.register 把 ModelAdmin 类绑定到 模型上,注册到Django的后台去。

其中

  • list_display
  • list_filter
  • search_fields
  • actions 存放自定义的”操作性方法“,比如我们需要的 ”申请借用“ 的功能

这里在 PhoneAdmin 中定义方法 apply_for_borrow, 在这个方法中我们进行”申请借用“ 资源的限制 (因为是从后台选择定义然后进行处理)

3.1、每次只能选择一个手机 len(queryset) 只能等于1

3.2、选择的手机状态只能是 ”空闲中“ 的

3.3、选择 ”一个空闲中“的手机之后,跳转到 ”借用“逻辑处理的view视图,进行实际的借用逻辑处理。

3.4、这里做了个特殊的处理,就是借用逻辑处理完毕之后,再跳回到当前后台的手机记录页面。

4、借用逻辑开发

这里先给出完整代码,然后进行分析说明

# cmdb/views.py
from django.shortcuts import render, HttpResponse, redirect
from django.contrib.auth.decorators import login_required
from cmdb.models import Phone, BorrowRecord
from django.utils import timezone
from django.http import HttpResponseRedirect
from django.contrib import messages


@login_required
def borrow_phone(request, pk):
    """
    申请借用手机视图
    """
    phone = Phone.objects.get(pk=pk)
    pr = BorrowRecord()
    pr.user = request.user
    pr.borrow_date = timezone.now()
    pr.phone = phone
    pr.save()
    
    phone.status = '被借走'
    phone.save()
    
    messages.success(request, '手机借用成功')
    return redirect(request.GET.get('next', 'admin:index'))

4.1、这里先获取到待借用的手机 (phone = Phone.objects.get(pk=pk))

4.2、然后新增借用记录 15到19行,其中配置了借用人(request.user)、借用时间 (timezone.now() 当期时间)已经借用的手机,就是第14行获取到的手机。

4.3、同时记得修改手机的状态,从 “空闲中“ 修改为 "被借走"

4.4、这里额外使用的 Django的message机制,通过它可以在Django后台进行页面消息提示 (第24行)

4.5、最后根据获取到的next 跳转回到之前的页面。

5、消息通知开发

这是主要是通过发送邮件,让管理员知道“谁在借用手机,借用的是哪个手机”,好提前做准备。

具体功能也是通过Django的 send_mail 函数来实现。

5.1、settings配置

# proj/settings.py
# 配置邮件信息
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qiye.163.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'ops@colinspace.com'
EMAIL_HOST_PASSWORD = 'xxxxxxxx'
DEFAULT_FROM_EMAIL = 'ops@colinspace.com'
# 管理员邮箱
ADMIN_EMAIL = 'admin@colinspace.com'

5.2、views中借用逻辑修改

# cmdb/views.pu
@login_required
def borrow_phone(request, pk):
    """
    申请借用手机视图
    """
    ... ...

    # 发送邮件逻辑
    subject = f'[{request.user}] 申请借用手机'
    message = f'[{request.user}] 申请借用手机 ({phone.brand} - {phone.model} - {phone.serial_number})'
    recipient_list = [settings.ADMIN_EMAIL]
    send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list)
    
    messages.success(request, '手机借用成功')
    return redirect(request.GET.get('next', 'admin:index'))

然后普通用户在后台申请借用手机之后,管理员就会收到如下的邮件信息

image.png

6、权限管控配置

主要是在Django Admin后台新增用户的时候,配置相关权限(User permissions) 如下图所示

image.png

只给 两个视图的view(查看)权限即可。

在ModelAdmin类中定义的方法,是没有做权限限制的

每个人都可以使用申请借用的功能

下图所示是普通用户James登录看到的效果,他只有 两个视图的view的权限

看到左侧没有”➕“ 不能新增模型记录,然后在列表的action中,只有 ”申请借用“ 选项,而没有默认的 ”Deleted select 测试手机管理“ 选项。

image.png

通过如上的开发和配置,我们就实现测试提出的 手机管理系统的基本需求。

然后给服务配置域名,就可以交付给测试组进行使用了。是不是很快就上手了一个小系统呢~

系统的详细代码详见 https://gitee.com/colin5063/django-examples/tree/main/django_phone_management (复制到浏览器再打开哦)

克隆到本地之后,按照 django_phone_management/ReadMe.md 提示进行操作即可运行项目。

有问题及时反馈哦~

如果你觉得有所收获,欢迎关注公众号"菩提老鹰"进行点赞和喜欢哦~

一起交流,分享知识,快乐生活,我是老鹰,我们下一期见~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容