Compare commits

...

10 Commits

2
.gitignore vendored

@ -22,3 +22,5 @@ pnpm-debug.log*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
*.log
db.sqlite3

@ -2,7 +2,7 @@
FROM python:3.7 FROM python:3.7
# 安装netcat # 安装netcat
RUN apt-get update && apt install -y netcat RUN apt-get update
# 可选:设置镜像源为国内 # 可选:设置镜像源为国内
COPY pip.conf /root/.pip/pip.conf COPY pip.conf /root/.pip/pip.conf
@ -26,6 +26,7 @@ RUN sed -i 's/\r//' ./start.sh
# 给start.sh可执行权限 # 给start.sh可执行权限
RUN chmod +x ./start.sh RUN chmod +x ./start.sh
RUN chmod 777 -R /home/myproject/logs/
EXPOSE 8000 EXPOSE 8000

@ -0,0 +1,2 @@
import pymysql
pymysql.install_as_MySQLdb()

@ -41,7 +41,9 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'django_filters', 'django_filters',
'corsheaders', 'corsheaders',
'app' 'app',
'event',
'user',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -53,6 +55,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'mymiddleware.middleware.CheckTokenMiddleware',
] ]
ROOT_URLCONF = 'TP_API.urls' ROOT_URLCONF = 'TP_API.urls'
@ -79,10 +82,21 @@ WSGI_APPLICATION = 'TP_API.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
# }
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.mysql',
'NAME': BASE_DIR / 'db.sqlite3', 'NAME': 'tp_test',
'USER': 'root',
'PASSWORD': 'Xfc980516',
'HOST': '127.0.0.1',
'PORT': '3306',
} }
} }
@ -138,7 +152,7 @@ CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_HEADERS = ["*"] CORS_ALLOW_HEADERS = ["*"]
CORS_ORIGIN_WHITELIST = () # CORS_ORIGIN_WHITELIST = ('*',)
# 对应的发送的请求的跨域 # 对应的发送的请求的跨域
CORS_ALLOW_METHODS = ( CORS_ALLOW_METHODS = (
'DELETE', 'DELETE',
@ -158,4 +172,74 @@ REST_FRAMEWORK = {
'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S", 'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S",
'DATE_FORMAT': "%Y-%m-%d", 'DATE_FORMAT': "%Y-%m-%d",
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
'EXCEPTION_HANDLER': 'app.exception.exception_handler',
# 'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 第一种jwt方式
# # 'rest_framework.authentication.SessionAuthentication', # 第二种session方式
# # 'rest_framework.authentication.BasicAuthentication', # 第三种Django的基本方式
# ),
#
# 'DEFAULT_PERMISSION_CLASSES': (
# 'rest_framework.permissions.IsAuthenticated',
# ),
}
# 配置日志
LOG_DIR = os.path.join(BASE_DIR, 'logs')
LOGGING = {
'version': 1, # 保留字
'disable_existing_loggers': False, # 是否禁用已经存在的日志实例
'formatters': { # 定义日志的格式
'standard': {
'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
'[%(levelname)s]%(message)s'
},
'simple': {
'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
},
'collect': {
'format': '%(message)s'
} }
},
'filters': { # 定义日志的过滤器
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 日志处理程序
'console': {
'level': 'DEBUG',
'filters': ['require_debug_true'], # 只有在Django debug为True时才在屏幕打印日志
'class': 'logging.StreamHandler',
'formatter': 'simple',
# 'filename': os.path.join(BASE_LOG_DIR, "tpservice.log")
},
'file': {
'level': 'INFO',
'class': 'concurrent_log_handler.ConcurrentRotatingFileHandler', # window多进程 需要 pip install concurrent-log-handler
'filename': os.path.join(BASE_DIR, "logs/debug.log"), # 日志文件
'backupCount': 10, # 保留的最大文件数,超过则删除日期最早的
'maxBytes': 1024 * 1024 * 10, # 文件大小
'formatter': 'standard',
'encoding': 'utf-8',
},
# 'file': {
# 'level': 'INFO',
# 'class': 'cloghandler.ConcurrentRotatingFileHandler', # linux多进程 需要 pip install ConcurrentLogHandler
# 'filename': os.path.join(BASE_DIR, "logs/debug.log"), # 日志文件
# 'backupCount': 10, # 保留的最大文件数,超过则删除日期最早的
# 'maxBytes': 1024 * 1024 * 10, # 文件大小
# 'formatter': 'standard',
# 'encoding': 'utf-8',
# },
},
'loggers': { # 日志实例 记录器
'mylogger': { # 默认的logger应用如下配置
'handlers': ['console', 'file'],
'level': 'DEBUG',
'propagate': True, # 是否向上一级logger实例传递日志信息
},
},
}
AUTH_USER_MODEL = 'user.UserProfile'

@ -23,7 +23,8 @@ from .settings import MEDIA_ROOT
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('api/', include('app.urls')) path('api/', include('app.urls')),
path('event/', include('event.urls')),
] ]

@ -30,21 +30,22 @@
- 返回值: - 返回值:
| 参数名 | 参数值 | 参数类型 | 描述说明 | | 参数名 | 参数值 | 参数类型 | 描述说明 |
| ------------- | ------------------------------------------------- | -------- | ------------------------ | | ---------------- | ------------------------------------------------- | -------- |--------------|
| uid | 1 | int | 自增 | | uid | 1 | int | 自增 |
| video_hash | 38fb463b135fa12534104f85492cc6f1 | string | 视频哈希值 | | video_hash | 38fb463b135fa12534104f85492cc6f1 | string | 视频哈希值 |
| record_time | 2023-05-26 13:09:05 | string | 记录仪时间 | | record_time | 2023-05-26 13:09:05 | string | 记录仪时间 |
| police_id | 00000001 | string | 警号 | | police_id | 00000001 | string | 警号 |
| event_type | 1 | string | 事件类型 | | event_type | 1 | string | 事件类型/车辆违法原因 |
| is_violation | true | bool | 是否违规 | | is_violation | true | bool | 执法人员是否违规 |
| small_image | http://192.168.0.47:8000/media/images/0000609.jpg | string | 缩略图 | | small_image | http://192.168.0.47:8000/media/images/0000609.jpg | string | 缩略图 |
| relative_time | 4.0 | float | 相对时间 | | relative_time | 4.0 | float | 相对时间 |
| video_dir | http://192.168.0.47:8000/media/video/B1.MP4 | string | 视频地址 | | video_dir | http://192.168.0.47:8000/media/video/B1.MP4 | string | 视频地址 |
| car_number | 苏a045689 | string | 车牌号 | | car_number | 苏a045689 | string | 车牌号 |
| ai_analysis | 违规 | string | 分析结果 | | ai_analysis | 违规 | string | 执法人员违规行为 |
| add_time | 2023-05-31 18:42:15 | string | 记录添加时间(自动添加) | | add_time | 2023-05-31 18:42:15 | string | 记录添加时间(自动添加) |
| update_time | 2023-05-31 18:42:15 | string | 记录更新时间(自动添加) | | update_time | 2023-05-31 18:42:15 | string | 记录更新时间(自动添加) |
| is_display | true | bool | 是否展示(自动添加) | | is_display | true | bool | 是否展示(自动添加) |
| is_illegal | True | bool | 行人是否违法 |
@ -237,4 +238,42 @@
| is_display | true | bool | 是否展示(自动添加) | | is_display | true | bool | 是否展示(自动添加) |
</details>
<details>
<summary>登录</summary>
- 请求方式POST
- 请求链接http://192.168.10.13:8000/api/login
- 请求body
```json
{
"username": "xfc",
"password": "Xfc980516"
}
```
| 参数名 | 参数值 | 是否必填 | 参数类型 | 描述说明 |
|----------|------------| -------- |--------|------|
| username | xfc | 是 | string | 用户名 |
| password | Xfc980516 | 是 | string | 密码 |
- 备注:无
- 返回值:
| 参数名 | 参数值 | 参数类型 | 描述说明 |
|-------------|-----------------------------------------|--------|--------------|
| success | True | bool | 成功 |
| msg | 登录成功 | string | 返回信息 |
| data | | dict | 返回数据 |
| username | xfc | string | 用户名 |
| roles | [] | list | 角色列表 |
| accessToken | eyJhbGciOiJIUzI1NiIsInR5cCI6 | string | token值 |
| expires | Wed Jul 5 16:03:31 2023 | string | token过期时间 |
</details> </details>

@ -1,3 +1,5 @@
from django.contrib import admin from django.contrib import admin
# Register your models here. # Register your models here.
from app.models import TP
admin.site.register(TP)

@ -0,0 +1,23 @@
import logging
from rest_framework.views import exception_handler as drf_exception_handler # drf原生处理异常函数取别名
from rest_framework.views import Response
from rest_framework import status
logger = logging.getLogger('mylogger')
def exception_handler(exc, context):
# drf的exception_handler做基础处理
response = drf_exception_handler(exc, context)
# 为空,进行自定义二次处理
logger.error(str(exc))
if response is None:
# print(exc) # 错误原因
# print(context) # 错误信息
# print('%s - %s - %s' % (context['view'], context['request'].method, exc))
return Response({
'detail': '服务器错误'
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True)
return response

@ -0,0 +1,40 @@
# Generated by Django 3.2.19 on 2023-06-30 16:19
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='TP',
fields=[
('uid', models.AutoField(primary_key=True, serialize=False)),
('video_hash', models.CharField(max_length=50, verbose_name='视频哈希')),
('record_time', models.DateTimeField(verbose_name='记录仪时间')),
('police_id', models.CharField(blank=True, max_length=50, null=True, verbose_name='警号')),
('event_type', models.CharField(max_length=50, verbose_name='事件类型/车辆违法原因')),
('is_violation', models.BooleanField(default=False, verbose_name='执法人员是否违规')),
('small_image', models.CharField(max_length=100, verbose_name='缩略图')),
('relative_time', models.FloatField(verbose_name='相对时间')),
('video_dir', models.CharField(max_length=100, verbose_name='视频路径')),
('car_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='车牌号')),
('ai_analysis', models.CharField(blank=True, max_length=255, null=True, verbose_name='分析结果')),
('add_time', models.DateTimeField(auto_now_add=True, verbose_name='加入时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('is_display', models.BooleanField(default=True, verbose_name='是否显示')),
('vehicle_color', models.CharField(blank=True, max_length=256, null=True, verbose_name='车辆颜色')),
('violation_reason', models.CharField(default='', max_length=512, verbose_name='执法人员违规原因')),
('is_illegal', models.BooleanField(default=False, verbose_name='车辆是否违法')),
],
options={
'db_table': 'app_tp',
'ordering': ['-uid'],
},
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.2.19 on 2023-06-30 16:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='tp',
name='video_hash',
field=models.CharField(default='', max_length=50, verbose_name='视频哈希'),
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.2.19 on 2023-06-30 16:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0002_alter_tp_video_hash'),
]
operations = [
migrations.AlterField(
model_name='tp',
name='video_hash',
field=models.CharField(max_length=50, verbose_name='视频哈希'),
),
]

@ -0,0 +1,26 @@
# Generated by Django 3.2.19 on 2023-07-03 17:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0003_alter_tp_video_hash'),
]
operations = [
migrations.RemoveField(
model_name='tp',
name='vehicle_color',
),
migrations.RemoveField(
model_name='tp',
name='violation_reason',
),
migrations.AlterField(
model_name='tp',
name='ai_analysis',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='执法人员违规行为'),
),
]

@ -0,0 +1,23 @@
# Generated by Django 3.2.19 on 2023-07-03 17:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0004_auto_20230703_1718'),
]
operations = [
migrations.AlterField(
model_name='tp',
name='is_illegal',
field=models.BooleanField(blank=True, null=True, verbose_name='车辆是否违法'),
),
migrations.AlterField(
model_name='tp',
name='is_violation',
field=models.BooleanField(blank=True, null=True, verbose_name='执法人员是否违规'),
),
]

@ -0,0 +1,23 @@
# Generated by Django 3.2.19 on 2023-07-04 11:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0005_auto_20230703_1727'),
]
operations = [
migrations.AlterField(
model_name='tp',
name='event_type',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='事件类型/车辆违法原因'),
),
migrations.AlterField(
model_name='tp',
name='video_hash',
field=models.CharField(max_length=1024, verbose_name='视频哈希'),
),
]

@ -1,36 +1,42 @@
from django.db import models from django.db import models
# Create your models here. # Create your models here.
class TP(models.Model): class TP(models.Model):
# uid # uid
uid = models.AutoField(primary_key=True) uid = models.AutoField(primary_key=True)
# 视频哈希 # 视频哈希
video_hash = models.CharField(max_length=50) video_hash = models.CharField(max_length=1024, verbose_name='视频哈希')
# 记录仪时间 # 记录仪时间
record_time = models.DateTimeField() record_time = models.DateTimeField(verbose_name='记录仪时间')
# 警号 # 警号
police_id = models.CharField(max_length=50) police_id = models.CharField(max_length=50, null=True, blank=True, verbose_name='警号') # 警号可为空可不传
# 事件类型 # 事件类型
event_type = models.CharField(max_length=50) event_type = models.CharField(max_length=50, verbose_name='事件类型/车辆违法原因', null=True, blank=True) # 还没迁移
# 是否违规 # 是否违规
is_violation = models.BooleanField() is_violation = models.BooleanField(verbose_name='执法人员是否违规', null=True, blank=True)
# 缩略图 # 缩略图
small_image = models.CharField(max_length=100) small_image = models.CharField(max_length=100, verbose_name='缩略图')
# 相对时间 # 相对时间
relative_time = models.FloatField() relative_time = models.FloatField(verbose_name='相对时间')
# 视频路径 # 视频路径
video_dir = models.CharField(max_length=100) video_dir = models.CharField(max_length=100, verbose_name='视频路径')
# 车牌号 # 车牌号
car_number = models.CharField(max_length=50) car_number = models.CharField(max_length=50, verbose_name='车牌号', null=True, blank=True) # 车牌可为空可不传
# 分析结果 # 分析结果
ai_analysis = models.CharField(max_length=255) ai_analysis = models.CharField(max_length=255, verbose_name='执法人员违规行为', null=True, blank=True) # 分析结果可为空可不传
# 加入时间 # 加入时间
add_time = models.DateTimeField(auto_now_add=True) add_time = models.DateTimeField(auto_now_add=True, verbose_name='加入时间')
# 更新时间 # 更新时间
update_time = models.DateTimeField(auto_now=True) update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
# 是否显示 # 是否显示
is_display = models.BooleanField(default=True) is_display = models.BooleanField(default=True, verbose_name='是否显示')
is_illegal = models.BooleanField(verbose_name='车辆是否违法', null=True, blank=True)
class Meta:
db_table = "app_tp"
# 排序 uid倒序
ordering = ['-uid']

@ -1,9 +1,11 @@
import datetime
from rest_framework import serializers from rest_framework import serializers
from django_filters.rest_framework import FilterSet from django_filters.rest_framework import FilterSet
import django_filters import django_filters
from app.models import TP from app.models import TP
import logging
logger = logging.getLogger('mylogger')
class SerialMyModel(serializers.ModelSerializer): class SerialMyModel(serializers.ModelSerializer):
class Meta: class Meta:
model = TP model = TP
@ -20,12 +22,37 @@ class SerialFilter(FilterSet):
record_time = django_filters.DateTimeFilter(field_name='record_time', lookup_expr='icontains') record_time = django_filters.DateTimeFilter(field_name='record_time', lookup_expr='icontains')
police_id = django_filters.CharFilter(field_name='police_id', lookup_expr='icontains') police_id = django_filters.CharFilter(field_name='police_id', lookup_expr='icontains')
event_type = django_filters.CharFilter(field_name='event_type', lookup_expr='icontains') event_type = django_filters.CharFilter(field_name='event_type', lookup_expr='icontains')
# 记录时间范围查询
start_time = django_filters.DateTimeFilter(field_name='record_time', lookup_expr='gte')
# end_time = django_filters.DateTimeFilter(field_name='record_time', lookup_expr='lte')
end_time = django_filters.DateTimeFilter(field_name='record_time', method='time_range_filter')
# todo bug: start_time 和 end_time同一天的情况 done
violation = django_filters.NumberFilter(field_name='is_violation', method='is_violation_query')
violation_type = django_filters.CharFilter(field_name='ai_analysis', lookup_expr='icontains')
def time_range_filter(self, queryset, name, value):
"""
@params queryset: 为TP.objects.all()返回的合集, 即视图类中的的queryset
@params name: 为field_name
@params value: 为前端通过end_time字段传过来的值
"""
return queryset.filter(record_time__lte=value + datetime.timedelta(days=1))
def is_violation_query(self, queryset, name, value):
if value == 2:
return queryset
elif value == 1:
return queryset.filter(is_violation=True)
elif value == 0:
return queryset.filter(is_violation=False)
else:
return queryset.filter(is_violation=True)
class Meta: class Meta:
# 指定模型 # 指定模型
models = TP models = TP
# 指定需要模糊查询的字段 # 指定需要模糊查询的字段
fields = ("record_time", "police_id", "event_type",) fields = ("record_time", "police_id", "event_type", "ai_analysis",)

@ -14,7 +14,7 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
# from django.contrib import admin # from django.contrib import admin
from django.urls import path, include from django.urls import path, include, re_path
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from app import views from app import views
@ -23,4 +23,7 @@ router.register('', views.ModelQuery)
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),
path('add_user', views.RegisterLoginViewSet.as_view({"post": "tp_register"})),
path('login', views.LoginView.as_view({"post": "tp_login"})),
path('events', views.ModelQuery.as_view({"get": "query_event"})),
] ]

@ -0,0 +1,31 @@
import time
import datetime
import jwt
from django.conf import settings
from rest_framework.response import Response
from django.contrib.auth.models import User
def generate_token(user):
"""
:param user: 用户对象
:return: 生成的token
"""
payload = {
'user_id': user.id,
'username': user.username,
'exp': datetime.datetime.utcnow() + datetime.timedelta(weeks=1) # token过期时间 1week
}
token = jwt.encode(payload=payload, key=settings.SECRET_KEY, algorithm='HS256')
return token
def decode_token_exp_time(token):
try:
res_dict = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
exp = res_dict.get('exp')
exp_time = time.ctime(exp)
return exp_time
except Exception as e:
return None

@ -1,4 +1,8 @@
import logging
from django.db.models import Count
from django.shortcuts import render from django.shortcuts import render
from django.views.decorators.http import require_http_methods
# Create your views here. # Create your views here.
from rest_framework import viewsets from rest_framework import viewsets
@ -6,11 +10,16 @@ from rest_framework.response import Response
from app.models import TP from app.models import TP
from app.serializers import SerialMyModel, SerialFilter from app.serializers import SerialMyModel, SerialFilter
from app.pagination import MyPageNumberPagination from app.pagination import MyPageNumberPagination
from user.models import UserProfile
from django.contrib.auth import authenticate, login, logout
from .utils import generate_token, decode_token_exp_time
logger = logging.getLogger('mylogger')
class ModelQuery(viewsets.ModelViewSet): class ModelQuery(viewsets.ModelViewSet):
# 查询类 # 查询类
queryset = TP.objects.all().order_by("uid") queryset = TP.objects.all().order_by("-uid") # 按照uid倒序
# 序列化类 # 序列化类
serializer_class = SerialMyModel serializer_class = SerialMyModel
# 分页类 # 分页类
@ -19,3 +28,77 @@ class ModelQuery(viewsets.ModelViewSet):
# 条件筛选 # 条件筛选
filterset_class = SerialFilter filterset_class = SerialFilter
def query_event(self, request, *args, **kwargs):
res = TP.objects.values('event_type').annotate(count=Count('event_type')).order_by('-count')
result = list(res)
data = dict()
for index, item in enumerate(result, 1):
data[index] = item.get('event_type')
response = {
'success': True,
'msg': '查询成功',
'data': data
}
return Response(response)
class RegisterLoginViewSet(viewsets.ModelViewSet):
def tp_register(self, request, *args, **kwargs):
"""注册 POST"""
# 判断用户是否为管理员
# user = request.user
# if not user.is_superuser:
# return Response({'msg': '您不是管理员,无权限添加成员'})
data = request.data
username = data.get('username')
password = data.get('password')
try:
if UserProfile.objects.filter(username=username).first():
return Response({'msg': '该用户名已存在,请换一个'})
UserProfile.objects.create_user(username=username, password=password)
return Response({'msg': '注册成功'})
except Exception as e:
logger.info(e)
response = {
"msg": f'注册失败, 原因:{e}'
}
return Response(response)
class LoginView(viewsets.ModelViewSet):
def tp_login(self, request, *args, **kwargs):
"""登录 POST"""
data = request.data
username = data.get('username')
password = data.get('password')
login_user = authenticate(username=username, password=password)
if login_user and login_user.is_active:
# 生成token
token = generate_token(login_user)
response = {
'success': True,
'msg': '登录成功',
'data': {
'username': login_user.username,
'roles': ['admin'] if login_user.is_superuser else ['common'],
'accessToken': token,
'expires': decode_token_exp_time(token)
}
}
return Response(response)
else:
response = {
'success': False,
'msg': '登录失败',
'data': {
'username': None,
'roles': [],
'accessToken': None,
'expires': None
}
}
return Response(response)
def tp_logout(self, request, *args, **kwargs):
"""登出 GET"""
pass

@ -0,0 +1,5 @@
from django.contrib import admin
# Register your models here.
from event.models import Event
admin.site.register(Event)

@ -0,0 +1,6 @@
from django.apps import AppConfig
class EventConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'event'

@ -0,0 +1,14 @@
import django_filters
from django_filters.rest_framework import FilterSet
from event.models import Event
class EventFilter(FilterSet):
event_name = django_filters.CharFilter(field_name='event_name', lookup_expr='icontains')
class Meta:
# 指定模型
models = Event
# 指定需要模糊查询的字段
fields = ("event_name",)

@ -0,0 +1,27 @@
# Generated by Django 3.2.19 on 2023-06-30 16:19
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Event',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event_name', models.CharField(default='', max_length=256, verbose_name='事件名')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
],
options={
'db_table': 'tp_event',
'ordering': ['-id'],
},
),
]

@ -0,0 +1,13 @@
from django.db import models
# Create your models here.
class Event(models.Model):
event_name = models.CharField(max_length=256, default='', verbose_name='事件名')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'tp_event'
ordering = ['-id']

@ -0,0 +1,8 @@
from rest_framework import serializers
from event.models import Event
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = "__all__"

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,10 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from event import views
router = DefaultRouter()
router.register('', views.EventViewSet)
urlpatterns = [
path('', include(router.urls)),
]

@ -0,0 +1,23 @@
from django.shortcuts import render
from rest_framework import viewsets
from app.pagination import MyPageNumberPagination
from event.filters import EventFilter
from event.models import Event
from event.serializers import EventSerializer
# Create your views here.
class EventViewSet(viewsets.ModelViewSet):
# 查询集
queryset = Event.objects.all().order_by('-id')
# 序列化器
serializer_class = EventSerializer
# 分页器
pagination_class = MyPageNumberPagination
# 过滤器
filterset_class = EventFilter

@ -0,0 +1,30 @@
import jwt
from django.conf import settings
from user.models import UserProfile
from django.http import HttpResponse, JsonResponse
from django.utils.deprecation import MiddlewareMixin
import logging
from rest_framework.response import Response
logger = logging.getLogger('mylogger')
class CheckTokenMiddleware(MiddlewareMixin):
def process_request(self, request):
# todo 登录时不需要校验token
path_info = request.path_info
if path_info.endswith('login'):
return
my_auth = request.META.get('HTTP_TOKEN')
if not my_auth:
return JsonResponse(data={'msg': '非法请求,请求头中未携带token'}, status=201)
try:
token = my_auth.split(' ')[1]
res_dict = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
except Exception as e:
logger.info(e)
return JsonResponse({'msg': f'非法token{e}'}, status=201)
# request.user = UserProfile.objects.filter(id=res_dict.get('user_id')).first()
# logger.info(res_dict)
return

Binary file not shown.

@ -4,5 +4,6 @@ python manage.py makemigrations&&
python manage.py migrate&& python manage.py migrate&&
uwsgi --ini /home/myproject/uwsgi.ini&& uwsgi --ini /home/myproject/uwsgi.ini&&
echo 'TP项目启动完成' echo 'TP项目启动完成'
tail -f /dev/null
exec "$@" exec "$@"

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

@ -0,0 +1,6 @@
from django.apps import AppConfig
class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'user'

@ -0,0 +1,48 @@
# Generated by Django 3.2.19 on 2023-06-30 16:19
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='UserProfile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('organization', models.CharField(blank=True, max_length=256, null=True, verbose_name='组织')),
('gender', models.IntegerField(choices=[(0, ''), (1, '')], default=1, verbose_name='性别')),
('phone_number', models.CharField(blank=True, max_length=12, null=True, verbose_name='手机号')),
('head_sculpture', models.CharField(blank=True, max_length=512, null=True, verbose_name='头像')),
('status', models.IntegerField(default=0, verbose_name='状态')),
('recorder_number', models.CharField(blank=True, max_length=256, null=True, verbose_name='执法记录仪编号')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'db_table': 'tp_user',
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]

@ -0,0 +1,20 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
# Create your models here.
class UserProfile(AbstractUser):
GENDER = ((0, ''), (1, ''))
organization = models.CharField(max_length=256, verbose_name='组织', null=True, blank=True)
gender = models.IntegerField(choices=GENDER, default=1, verbose_name='性别')
phone_number = models.CharField(max_length=12, verbose_name='手机号', null=True, blank=True)
head_sculpture = models.CharField(max_length=512, verbose_name='头像', blank=True, null=True)
status = models.IntegerField(verbose_name='状态', default=0)
recorder_number = models.CharField(max_length=256, verbose_name='执法记录仪编号', null=True, blank=True)
class Meta:
db_table = 'tp_user'

@ -0,0 +1,278 @@
from django.test import TestCase
# Create your tests here.
l1 = [
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-14 15:43:25",
"police_id": "8888888",
"event_type": "卡车",
"is_violation": False,
"small_image": "http://192.168.10.28:8000/media/images/B2_006.png",
"relative_time": 6.0,
"video_dir": "http://192.168.10.28:8000/media/videos/B2.mp4",
"car_number": "赣A·98980",
"ai_analysis": "",
"add_time": "2023-06-12 09:17:45",
"update_time": "2023-06-27 02:36:51",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-14 15:43:24",
"police_id": "8888888",
"event_type": "卡车",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/B2_004.png",
"relative_time": 4.0,
"video_dir": "http://192.168.10.28:8000/media/videos/B2.mp4",
"car_number": "赣A·98980",
"ai_analysis": "",
"add_time": "2023-06-12 09:16:41",
"update_time": "2023-06-27 02:36:51",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2023-05-14 17:27:40",
"police_id": "",
"event_type": "推搡",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/shoving_005_1.png",
"relative_time": 9.0,
"video_dir": "http://192.168.10.28:8000/media/videos/shoving.mp4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 07:13:24",
"update_time": "2023-06-27 02:36:51",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2023-05-14 17:27:40",
"police_id": "",
"event_type": "推搡",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/shoving_009_1.png",
"relative_time": 9.0,
"video_dir": "http://192.168.10.28:8000/media/videos/shoving.mp4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 07:13:19",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2023-05-14 17:27:40",
"police_id": "",
"event_type": "推搡",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/shoving_009.png",
"relative_time": 9.0,
"video_dir": "http://192.168.10.28:8000/media/videos/shoving.mp4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 07:12:34",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2023-05-14 17:27:40",
"police_id": "",
"event_type": "推搡",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/shoving_005.png",
"relative_time": 5.0,
"video_dir": "http://192.168.10.28:8000/media/videos/shoving.mp4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 07:10:03",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-14 17:27:40",
"police_id": "8888888",
"event_type": "未戴头盔",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G2_018_1.png",
"relative_time": 18.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G2.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:53:50",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-14 17:27:40",
"police_id": "",
"event_type": "未戴头盔",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G2_018.png",
"relative_time": 18.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G2.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:53:26",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:42:48",
"police_id": "0890151",
"event_type": "未戴头盔以及载人",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_024_1.png",
"relative_time": 24.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:52:12",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:42:48",
"police_id": "0890151",
"event_type": "未戴头盔以及载人",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_024.png",
"relative_time": 24.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:51:33",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:42:46",
"police_id": "0890151",
"event_type": "未戴头盔以及载人",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_022.png",
"relative_time": 22.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:50:53",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:42:28",
"police_id": "0890151",
"event_type": "未戴头盔以及载人",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_004.png",
"relative_time": 4.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:49:36",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:44:05",
"police_id": "0890151",
"event_type": "未戴头盔",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_141_1.png",
"relative_time": 101.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:48:34",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:44:05",
"police_id": "0890151",
"event_type": "未戴头盔",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_141.jpg",
"relative_time": 141.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:46:45",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 07:42:26",
"police_id": "0890151",
"event_type": "未戴头盔以及载人",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/G1_002.png",
"relative_time": 2.0,
"video_dir": "http://192.168.10.28:8000/media/videos/G1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:45:39",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 10:36:13",
"police_id": "6666666",
"event_type": "未戴头盔",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/B1_056.png",
"relative_time": 56.0,
"video_dir": "http://192.168.10.28:8000/media/videos/B1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:44:04",
"update_time": "2023-06-27 02:36:52",
"is_display": True
},
{
"video_hash": "vbhdrbvcw",
"record_time": "2022-07-15 10:36:13",
"police_id": "6666666",
"event_type": "未戴头盔",
"is_violation": True,
"small_image": "http://192.168.10.28:8000/media/images/056.png",
"relative_time": 56.0,
"video_dir": "http://192.168.10.28:8000/media/videos/B1.MP4",
"car_number": "",
"ai_analysis": "",
"add_time": "2023-06-12 06:18:40",
"update_time": "2023-06-27 02:36:52",
"is_display": True
}
]
l2 = []
from app.models import TP
def import_data(data):
try:
for item in data:
TP.objects.create(**item)
return
except Exception as e:
print(e)
return
if __name__ == '__main__':
import_data(l1)

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

@ -9,6 +9,7 @@ chdir=%(base)/%(project)
module=TP_API.wsgi:application module=TP_API.wsgi:application
master=True master=True
processes=2 processes=2
threads=4
http=0.0.0.0:8000 http=0.0.0.0:8000
@ -36,3 +37,6 @@ reload-mercy = 10
#设置工作进程使用虚拟内存超过N MB就回收重启 #设置工作进程使用虚拟内存超过N MB就回收重启
reload-on-as= 1024 reload-on-as= 1024
# 序列化接受的内容,如果可能的话
thunder-lock=true
Loading…
Cancel
Save