【Python+Django】一个简单停车场管理系统的设计及代码实现

本文利用Python的Django框架从0开始最终实现一个简单的Web 停车场管理系统。


目前一个典型的停车场管理包含如下几个功能:

1、扫描车牌识别自动出入场

2、会员管理(充值,提醒充值。。等)

3、收费(如果是有效期内的会员就免费)

为了实现上面几个功能,我们先简单的做下数据库和页面的设计。

数据库设计

数据库的话可以设计以下几个:

会员表:

车牌,姓名,手机号,会员起始日期,会员截止日期

用于会员的到期提醒,充值等管理

出入库记录表:

车牌,入场日期时间,出场日期时间,付款日期时间,付款金额

用于出入场记录及收费管理

页面功能设计

简单对系统做一个页面的结构划分

  • 停车场管理系统​

  • 会员管理

  • 会员充值

  • 会员查看

  • 车辆入场管理

  • ​车牌识别

  • ​入场记录

  • 车辆出场管理

  • ​车牌识别

  • ​出场记录

  • ​计算费用

  • 收费管理

系统实现

初步整理了需求后,我们直接开始撸代码。

创建项目

django-admin startproject DjangoPark2023

进入项目文件夹

cd DjangoPark2023

创建虚拟环境

python -m venv venv

进入虚拟环境

venv\Scripts\activate.bat

在虚拟环境中安装Django

pip install django

创建app

Django框架下的核心的模型和视图都需要在app中实现,我们简单点就创建一个app名为app01,实际项目中可以根据模块创建多个app。

python manage.py startapp app01

安装app

在文件 DjangoPark2023/settings.py 中更新代码如下

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01'   #增加此项
]

截止到目前的文件结构

定义模型

根据我们前面的数据库

app01/models.py

from django.db import models

# Create your models here.

class vip_uer(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    carnum = models.CharField(max_length=32, unique=True, verbose_name='车牌号')
    phone = models.CharField(max_length=32, verbose_name='手机号')
    begintime = models.DateTimeField(auto_now=False, auto_now_add=False)
    endtime = models.DateTimeField(auto_now=False, auto_now_add=False)

class car_record(models.Model):
    carnum = models.CharField(max_length=32, verbose_name='车牌号')
    intime = models.DateTimeField(auto_now=False, auto_now_add=False, verbose_name='入场时间')
    outtime = models.DateTimeField(auto_now=False, auto_now_add=False, verbose_name='出场时间', null=True, blank=True)
    paytime = models.DateTimeField(auto_now=False, auto_now_add=False ,verbose_name='收费时间', null=True, blank=True)
    amount = models.IntegerField(verbose_name='收费金额', null=True, blank=True)

安装连接MySQL的包

pip install pymysql

引入pymysql

DjangoPark2023/__init__.py

import pymysql
pymysql.install_as_MySQLdb()

MySQL的安装就不详细讲了,大家自行安装。

手工创建一个数据库,名字为:djangopark2023

连接MySQL数据库配置

DjangoPark2023/settings.py

# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',    # 数据库引擎
        'NAME': 'djangopark2023', # 数据库名称
        'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1 
        'PORT': 3306, # 端口 
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123456', # 数据库密码
    }
}

迁移模型

python manage.py makemigrations

更新迁移表

python manage.py migrate

数据表创建成功

创建超级用户

python manage.py createsuperuser

用户名:admin

密码:123456

运行服务器

python manage.py runserver

输入后台网址看下:http://127.0.0.1:8000/admin/

登录后没有显示自定义的模型,还需要注册模型到后台。

模型注册到admin后台

app01/admin.py

from django.contrib import admin

# Register your models here.
# 别忘了导入models
from app01.models import vip_uer
# 注册模型到admin中
admin.site.register(vip_uer)

添加一条VIP记录

功能和页面实现

会员管理

会员充值:

充值时选择充值天数,30天,90天,180天,360天,或自定义

如果车牌不存在,则添加一条会员记录,起始时间为现在,截止时间为现在+套餐天数。

如果车牌已存在,没过期,则截止时间 加上 套餐天数,如果过期了,则更新起始时间为现在,截止时间为现在+套餐天数。

前端网页模板

新建文件夹templates用于管理模板文件。

然后配置下模板位置

import os
*...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 添加此项
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

接着在templates创建模板文件:这里我们未来快速实现功能,暂时先直接在线引入bootstrap静态文件。

templates/recharge.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
        <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
    <title>会员充值</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-6">
            <br>
            <!-- 充值的表单 -->
            <form method="post" action=".">
                <!-- Django中需要POST数据的地方都必须有csrf_token -->
                {% csrf_token %}
                <div class="form-group">
                    <!-- 标签 -->
                    <label for="title">车牌号</label>
                    <!-- 文本框 -->
                    <input type="text" class="form-control" id="carnum" name="carnum">
                </div>
                <!-- 充值套餐 -->
                <div class="form-group">
                    <label for="body">充值天数</label>
                    <!-- 文本区域 -->
                    <input type="text" class="form-control" id="chargedays" name="chargedays" rows="6">
                </div>
                <!-- 提交按钮 -->
                <button type="submit" class="btn btn-primary">提交充值</button>
            </form>
        </div>
    </div>
</div>
</body>
</html>

视图函数功能实现:

app01/views.py

from django.http import HttpResponse
from django.shortcuts import render
import datetime
from app01 import models
from .models import vip_uer,car_record
# Create your views here.

def Recharge(request):
    if request.method == 'POST':
        chargedays = int( request.POST.get('chargedays') )
        carnum = request.POST.get('carnum')
        print(chargedays)
        days = datetime.timedelta(days=chargedays)
        if models.vip_uer.objects.filter(carnum=carnum):
            vip = vip_uer.objects.get(carnum=carnum)
            endtime = vip.endtime + days
            print(vip.endtime)
            models.vip_uer.objects.update(carnum=carnum, endtime = endtime)
        else:
            begtime = datetime.datetime.now()
            endtime = begtime + days
            models.vip_uer.objects.create(carnum=carnum, begintime = begtime ,endtime=endtime)
        return HttpResponse("充值成功!")
    else:
        return render(request, 'recharge.html')

路由配置

DjangoPark2023/urls.py 中更新如下代码,配置对应的路由规则。

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('recharge/', views.Recharge), #添加如下项
]

重新运行服务器

输入地址:http://127.0.0.1:8000/recharge/
输入车牌号和充值天数后提交充值后。


基础的架构打好了,接下来就是各种功能视图和模板的实现了,有时间再继续更!


继续:

车辆入场管理

车辆入场核心涉及两个功能点:车牌识别,入场记录。

车牌识别,我们直接通过选择图片模拟车牌扫描的动作,识别到车牌后,再通过车辆入场按钮完成车辆的入场登记。

车牌识别

实现车牌识别我们就没必要直接自己实现了,直接调Open CV来实现的话太费劲。

我们直接调百度现有的接口来实现就快很多了,详细的实现过程请参考如下链接。

实现的大概思路是我们网页端先导入一张图片,点击识别图片的时候,Django后端获取图片并存储起来,然后调用百度的图像识别接口识别我们的存储图片,返回对应的车牌信息给到网页前端。

简单一点来说调用百度接口需要做如下动作:

1、安装百度图像识别包:pip install baidu_aip

2、安装文件编码包 chardet :pip install chardet

3、安装图片处理包 Pillow :pip install Pillow

接着我们新建模型用于处理识别的图片:

app01/models.py

class License_plate(models.Model):
    car_img = models.ImageField(upload_to='car_imgs',unique=True, blank=True, null=True)
    car_num = models.CharField(max_length=32, unique=True, verbose_name='车牌号', null=True)
    color = models.CharField(max_length=32, verbose_name='车牌颜色')

更新并迁移表

python manage.py makemigrations

python manage.py migrate

然后定义一个函数调用百度接口

先引入AipOC

from aip import AipOcr

然后定义一个函数Park_discern调用函数识别图像,返回识别的内容信息。

from aip import AipOcr
def Park_discern(image):
    APP_ID = '自己的ID'
    API_KEY = '自己的KEY'
    SECRET_KEY = '自己的KEY'
    # 创建客户端对象
    client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
    # 建立连接的超时时间,单位为毫秒
    client.setConnectionTimeoutInMillis(5000)
    # 通过打开的连接传输数据的超时时间,单位为毫秒
    client.setSocketTimeoutInMillis(5000)
    res = client.licensePlate(image)
    return res

再定义一个函数 car_in,前端在点击图像识别按钮时调用函数根据前端选择的图片实现图像识别,将识别的内容返回给网页。

def car_in(request):
    if request.method == 'POST':
        # 读取图片
        img = request.FILES.get('car_img')
        if img == None:
            # 没有选择图片,而直接点击检测
            error = '请选择一张图片!'
            return render(request, 'car_in.html', {'error': error})
        else:
            try:
                # 将图片数据存起来
                new_car = models.License_plate.objects.create(car_img=img)

                # 定义读取图片函数
                def get_file_content(filePath):
                    with open(filePath, 'rb') as fp:
                        return fp.read()
                #生成图片地址
                url = './media/' + str(new_car.car_img)
                # 读取图片信息
                image = get_file_content(url)
                # 调用接口识别车牌
                res = Park_discern(image)
                #车牌号
                carnum = res['words_result']['number']
                #车牌颜色
                color = res['words_result']['color']
                try:
                    # 车牌是否识别过
                    is_carnum = models.License_plate.objects.get(car_num=carnum)
                    if is_carnum:
                        #识别过了的直接从数据库读取历史数据并删除当前存储的图片数据和文件
                        new_car.car_img = is_carnum.car_img
                        print(new_car.id )
                        models.License_plate.objects.filter(id=new_car.id ).delete()
                except models.License_plate.DoesNotExist:
                    # 没识别过,则保存车牌和颜色信息
                    new_car.color = color
                    new_car.car_num = carnum
                    new_car.save()
                    # return redirect('carnum_add')
                    print(new_car.car_img)
                return render(request,'car_in.html',{'carport_url':new_car.car_img,'carnum':carnum,'color':color})
            except Exception as e:
                return HttpResponse('识别发生错误!')
    return render(request, 'car_in.html',{'carport_url':'car_imgs/intro.jpg'})

入场登记

再定义一个函数carin_update,点击车辆入场按钮时登记车辆入场记录。

def carin_update(request):
    if request.method == 'POST':
        carnum = request.POST.get('carnum')
        # tz = pytz.timezone('Asia/Shanghai')
        new_intime = timezone.now()
        print(new_intime)
        models.car_record.objects.create(carnum=carnum, intime=new_intime)
        if models.vip_uer.objects.filter(carnum=carnum):
            vip = vip_uer.objects.get(carnum=carnum)
            # now = datetime.now(timezone.utc)
            endtime = vip.endtime
            remain_days = endtime - new_intime
            remain_days = str(remain_days.days)
            context = '会员车辆' + carnum + '欢迎您!'  + '剩余会员天数:' + remain_days
            print(context)
            return HttpResponse(context)
        else:
            return HttpResponse("临时车辆,欢迎入场!")

车牌识别和车辆入场的功能我们都放到一个模板里面:templates/car_in.html

<!-- 网站主语言 -->
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">

<body>

<div class="container">
    <div class="row">
        <div class="col-xl-10">
            <div class="content-box-large">
                <div class="panel-body">
                    <div class="card-body">
                        <label>检测图片</label>
                        <form enctype="multipart/form-data" action="" method="post">
                            {% csrf_token %}
                            {#                            <label for="car_img"><img id="imgforshow" src="/static/imgs/intro.jpg"#}
                            <label for="car_img"><img id="imgforshow" src="/media/{{ carport_url }}"
                                                      style="width: 350px; height: 200px; border:
                                                                 1px solid black; cursor: pointer"></label>
                            <input type="file" name="car_img" id="car_img" style="display: none;"><br>
                            <div class="form-group">
                                <label>检测结果:车牌号</label>
                                <input class="form-control" type="text" name="carnum" value="{{ carnum }}">
                                <label>检测结果:车牌颜色</label>
                                <input class="form-control" type="text" name="color" value="{{ color }}">
                            </div>
                            <div class="form-group">
                                <button class="btn btn-primary" type="submit">识别车牌</button>
                                <button class="btn btn-primary" formaction="/carin_update/" formmethod="post">车辆入场
                                </button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery.js"></script>
<!-- jQuery UI -->
<script src="https://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script>
    $("#car_img").change(function () {
        var rd_img = new FileReader();
        rd_img.readAsDataURL(this.files[0]);
        rd_img.onload = function () {
            $("#imgforshow").attr("src", rd_img.result);
        };
    });
</script>
</body>

</html>

选择图片,点击识别车牌,可以识别到车牌号和车牌颜色。

点击车辆入场,如果是会员则会提示剩余会员天数否则提示临时车辆。

车辆出场管理

车辆出场基本和入场差不多,识别车辆功能,然后更新出场记录。

不过我们在更新出场记录的时候,需要先找到扫描到的车牌最近的一次入场记录。

然后计算出停车时长,出场之前需要判断是否为会员,会员直接出场,否则需要先付款。然后才能出场。

分别编写视图函数如下:

def car_out(request):
    if request.method == 'POST':
        # 读取图片
        img = request.FILES.get('car_img')
        if img == None:
            # 没有选择图片,而直接点击检测
            error = '请选择一张图片!'
            return render(request, 'car_in.html', {'error': error})
        else:
            try:
                # 将图片数据存起来
                new_car = models.License_plate.objects.create(car_img=img)
                # 定义读取图片函数
                def get_file_content(filePath):
                    with open(filePath, 'rb') as fp:
                        return fp.read()
                #生成图片地址
                url = './media/' + str(new_car.car_img)
                # 读取图片信息
                image = get_file_content(url)
                # 调用接口识别车牌
                res = Park_discern(image)
                #车牌号
                carnum = res['words_result']['number']
                #车牌颜色
                color = res['words_result']['color']
                try:
                    # 车牌是否识别过
                    is_carnum = models.License_plate.objects.get(car_num=carnum)
                    if is_carnum:
                        #识别过了的直接从数据库读取历史数据并删除当前存储的图片数据和文件
                        new_car.car_img = is_carnum.car_img
                        print(new_car.id )
                        models.License_plate.objects.filter(id=new_car.id ).delete()
                except models.License_plate.DoesNotExist:
                    # 没识别过,则保存车牌和颜色信息
                    new_car.color = color
                    new_car.car_num = carnum
                    new_car.save()
                    # return redirect('carnum_add')
                    print(new_car.car_img)
                return render(request,'car_out.html',{'carport_url':new_car.car_img,'carnum':carnum,'color':color})
            except Exception as e:
                return HttpResponse('识别发生错误!')
    return render(request, 'car_out.html',{'carport_url':'car_imgs/intro.jpg'})

def carout_update(request):
    if request.method == 'POST':
        carnum = request.POST.get('carnum')
        new_outtime = timezone.now()
        print(new_outtime)
        new_car_record = car_record.objects.filter(carnum=carnum).order_by('outtime')
        out_car = new_car_record[0]
        out_car.carnum = carnum
        out_car.outtime = new_outtime
        out_car.save()
        if models.vip_uer.objects.filter(carnum=carnum):
            vip = vip_uer.objects.get(carnum=carnum)
            print(vip)
            # now = datetime.now(timezone.utc)
            endtime = vip.endtime
            remain_days = endtime - new_outtime
            remain_days = str(remain_days.days)
            print(remain_days)
            context = '会员车辆' + carnum + '一路顺风!'  + '剩余会员天数:' + remain_days
            print(context)
            return HttpResponse(context)
        else:
            return HttpResponse("临时车辆,一路顺风!")

模板templates/car_out.html:

<!-- 网站主语言 -->
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- jQuery UI -->
    <link href="https://code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" media="screen">
    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
</head>

<body>
<div class="container">
    <div class="row">
        <div class="col-md-10">
            <div class="content-box-large">
                <div class="panel-body">
                    <div class="card-body">
                        <label>检测图片</label>
                        <form enctype="multipart/form-data" action="" method="post">
                            {% csrf_token %}
{#                            <label for="car_img"><img id="imgforshow" src="/static/imgs/intro.jpg"#}
                            <label for="car_img"><img id="imgforshow" src="/media/{{ carport_url }}"
                                                      style="width: 350px; height: 200px; border:
                                                                 1px solid black; cursor: pointer"></label>
                            <input type="file" name="car_img" id="car_img" style="display: none;"><br>
                            <div class="form-group">
                                <label>检测结果:车牌号</label>
                                <input class="form-control" type="text" name="carnum" value="{{ carnum }}">
                                <label>检测结果:车牌颜色</label>
                                <input class="form-control" type="text" name="color" value="{{ color }}">
                            </div>
                            <div class="form-group">
                                <button class="btn btn-primary" type="submit">识别车牌</button>
                                <button class="btn btn-primary" formaction="/carout_update/" formmethod="post">车辆出场</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery.js"></script>
<!-- jQuery UI -->
<script src="https://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script>
    $("#car_img").change(function () {
        var rd_img = new FileReader();
        rd_img.readAsDataURL(this.files[0]);
        rd_img.onload = function (){
            $("#imgforshow").attr("src", rd_img.result);
        };
    });
</script>
</body>

</html>

关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

对于0基础小白入门:

如果你是零基础小白,想快速入门Python是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以找到适合自己的学习方案

包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、机器学习等习教程。带你从零基础系统性的学好Python!

零基础Python学习资源介绍

👉Python学习路线汇总👈

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取哈)

👉Python必备开发工具👈

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

👉Python学习视频600合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

👉实战案例👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
在这里插入图片描述

👉100道Python练习题👈

检查学习结果。

👉面试刷题👈

在这里插入图片描述

在这里插入图片描述

这份完整版的Python全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

  • 6
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个很有趣的话题。首先,让我们来简单介绍一下智能停车系统的基本功能。 智能停车系统主要包括三个模块:车辆入场管理、车位状态监控和车辆出场管理。 车辆入场管理:当车辆进入停车场时,需要通过识别车牌等方式获取车辆信息,并将其记录在系统中。此外,系统还需要为车辆分配一个可用的停车位,并将该停车位的状态从“可用”修改为“已占用”状态。 车位状态监控:系统需要实时监控停车位状态,当有车辆离开时,需要将该停车位的状态从“已占用”修改为“可用”状态,并更新车位的使用情况。 车辆出场管理:当车辆准备离开停车场时,需要通过识别车牌等方式确认车辆信息,并计算出停车费用。此外,系统还需要将该车辆的信息系统中删除,并将该停车位的状态从“已占用”修改为“可用”状态。 接下来是实现的步骤: 1. 车牌识别模块:使用OpenCV库来实现车牌识别功能。 2. 车位状态监控模块:使用传感器或摄像头来实现停车位状态的实时监控。 3. 数据库管理模块:使用MySQL或SQLite等数据库来管理车辆信息和停车位状态等信息。 4. 界面设计模块:使用PyQt或Tkinter等库来设计用户界面,实现用户与系统的交互。 5. 支付模块:使用支付宝、微信等支付平台来实现车辆缴纳停车费用的功能。 以上就是一个基本的智能停车系统设计实现步骤。当然,这只是一个简单的介绍,实际的开发过程中还需要考虑很多细节和问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值