django3.1 将 os.path 切换到了更现代和简洁的pathlib

Django3.1版本引入了异步视图和中间件支持,异步测试,JSONField适用于所有数据库后端,更新了管理页面等。新版本使用pathlib简化了目录路径操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是Django 3.0版本:

# settings.py
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

这是新的Django 3.1版本:

# settings.py
from pathlib import Path

BASE_DIR = Path(__file__).resolve(strict=True).parent.parent

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

Django 3.1将在2020年8月初发布,它有很多主要的新特性和一些小的改进,包括异步视图和中间件支持,异步测试,用于所有支持的数据库后端(不仅仅是PostgreSQL)的JSONField,一个更新的管理页面,等等。

import os import time import cv2 import numpy as np import base64 import json import threading from .page_4_1_auto_set import image_detect from django.conf import settings from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render, redirect from django.contrib import messages from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.tokens import default_token_generator from django.utils.encoding import force_bytes, force_str from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.core.mail import send_mail from django.contrib.auth.models import User from .models import UserInfo from ultralytics import YOLO from django.forms import Form, FileField from django.contrib.auth.forms import AuthenticationForm from django.http import JsonResponse, StreamingHttpResponse class VideoUploadForm(Form): video = FileField() def wechat_login(request): code = request.GET.get(&#39;code&#39;) if code: # 获取 access_token url = f&#39;https://api.weixin.qq.com/sns/oauth2/access_token?appid={settings.WECHAT_APPID}&secret={settings.WECHAT_SECRET}&code={code}&grant_type=authorization_code&#39; import requests response = requests.get(url) data = response.json() if &#39;access_token&#39; in data: access_token = data[&#39;access_token&#39;] openid = data[&#39;openid&#39;] # 获取用户信息 user_info_url = f&#39;https://api.weixin.qq.com/sns/userinfo?access_token={access_token}&openid={openid}&#39; user_info_response = requests.get(user_info_url) user_info = user_info_response.json() # 处理用户信息,例如创建或登录用户 # ... return redirect(&#39;home&#39;) else: # 重定向到微信授权页面 authorize_url = f&#39;https://open.weixin.qq.com/connect/oauth2/authorize?appid={settings.WECHAT_APPID}&redirect_uri={settings.WECHAT_REDIRECT_URI}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect&#39; return redirect(authorize_url) def register(request): if request.method == &#39;POST&#39;: username = request.POST.get(&#39;username&#39;) email = request.POST.get(&#39;email&#39;) password1 = request.POST.get(&#39;password1&#39;) password2 = request.POST.get(&#39;password2&#39;) # 检查用户名是否已存在 if UserInfo.objects.filter(user__username=username).exists(): messages.error(request, &#39;用户名已注册,请选择其他用户名!&#39;) return render(request, &#39;register.html&#39;, { &#39;username&#39;: username, &#39;email&#39;: email, &#39;error&#39;: &#39;username_exists&#39; }, status=400) # 检查用户名长度 if len(username) < 3: messages.error(request, &#39;用户名至少3个字符!&#39;) return render(request, &#39;register.html&#39;, { &#39;username&#39;: username, &#39;email&#39;: email, &#39;error&#39;: &#39;username_short&#39; }, status=400) # 检查邮箱是否已存在 if UserInfo.objects.filter(email=email).exists(): messages.error(request, &#39;邮箱已注册,请使用其他邮箱!&#39;) return render(request, &#39;register.html&#39;, { &#39;username&#39;: username, &#39;email&#39;: email, &#39;error&#39;: &#39;email_exists&#39; }, status=400) # 检查邮箱格式 import re if not re.match(r&#39;^[^\s@]+@[^\s@]+\.[^\s@]+$&#39;, email): messages.error(request, &#39;请输入有效的邮箱地址!&#39;) return render(request, &#39;register.html&#39;, { &#39;username&#39;: username, &#39;email&#39;: email, &#39;error&#39;: &#39;email_invalid&#39; }, status=400) # 检查密码复杂度 special_char_regex = re.compile(r&#39;[!@#$%^&*(),.?":{}|<>]&#39;) if len(password1) < 8 or not special_char_regex.search(password1): messages.error(request, &#39;密码长度至少为8个字符,且必须包含特殊字符!&#39;) return render(request, &#39;register.html&#39;, { &#39;username&#39;: username, &#39;email&#39;: email, &#39;error&#39;: &#39;password_weak&#39; }, status=400) # 创建新用户 try: user = User.objects.create_user(username=username, email=email, password=password1) UserInfo.objects.create(user=user, email=email) messages.success(request, &#39;注册成功!&#39;) return redirect(&#39;login&#39;) except Exception as e: messages.error(request, f&#39;注册失败:{str(e)}&#39;) return render(request, &#39;register.html&#39;, status=500) return render(request, &#39;register.html&#39;) import logging logger = logging.getLogger(__name__) def user_login(request): if request.method == &#39;POST&#39;: form = AuthenticationForm(request, data=request.POST) if form.is_valid(): username = form.cleaned_data.get(&#39;username&#39;) password = form.cleaned_data.get(&#39;password&#39;) user = authenticate(username=username, password=password) if user is not None: login(request, user) next_url = request.GET.get(&#39;next&#39;) if next_url: return redirect(next_url) return redirect(&#39;home&#39;) else: logger.error(f"认证失败,用户名: {username}") messages.error(request, &#39;用户名或密码错误,请重试。&#39;) else: form = AuthenticationForm() return render(request, &#39;login.html&#39;, {&#39;form&#39;: form}) @login_required def user_logout(request): logout(request) messages.success(request, &#39;您已成功退出登录。&#39;) return redirect(&#39;login&#39;) def check_username(request): username = request.GET.get(&#39;username&#39;) exists = UserInfo.objects.filter(user__username=username).exists() return JsonResponse({ &#39;exists&#39;: exists, &#39;valid&#39;: len(username) >= 3 if username else False }) def check_email(request): email = request.GET.get(&#39;email&#39;) exists = UserInfo.objects.filter(email=email).exists() import re return JsonResponse({ &#39;exists&#39;: exists, &#39;valid&#39;: bool(re.match(r&#39;^[^\s@]+@[^\s@]+\.[^\s@]+$&#39;, email)) if email else False }) def password_reset(request): if request.method == &#39;POST&#39;: form = PasswordResetForm(request.POST) if form.is_valid(): email = form.cleaned_data.get(&#39;email&#39;) try: user = User.objects.get(email=email) # 生成重置密码的 token uid token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) # 构建重置密码的链接 from django.urls import reverse reset_url = request.build_absolute_uri(reverse(&#39;password_reset_confirm&#39;, args=[uid, token])) # 发送重置密码的邮件 send_mail( &#39;重置密码&#39;, f&#39;请点击以下链接重置您的密码:{reset_url}&#39;, settings.EMAIL_HOST_USER, [email], fail_silently=False, ) messages.success(request, &#39;重置密码的邮件已发送,请检查您的邮箱。&#39;) return redirect(&#39;login&#39;) except User.DoesNotExist: messages.error(request, &#39;该邮箱未注册。&#39;) else: form = PasswordResetForm() return render(request, &#39;password_reset.html&#39;, {&#39;form&#39;: form}) def password_reset_confirm(request, uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, User.DoesNotExist): user = None if user is not None and default_token_generator.check_token(user, token): if request.method == &#39;POST&#39;: new_password1 = request.POST.get(&#39;new_password1&#39;) new_password2 = request.POST.get(&#39;new_password2&#39;) if new_password1 == new_password2: user.set_password(new_password1) user.save() messages.success(request, &#39;密码重置成功,请使用新密码登录。&#39;) return redirect(&#39;login&#39;) else: messages.error(request, &#39;两次输入的密码不一致,请重新输入。&#39;) return render(request, &#39;password_reset_confirm.html&#39;, {&#39;uidb64&#39;: uidb64, &#39;token&#39;: token}) else: messages.error(request, &#39;重置密码链接无效,请重新申请。&#39;) return redirect(&#39;password_reset&#39;) # @login_required def home(request): return render(request, &#39;home.html&#39;, {}) # @login_required def show_data_html(request): return render(request, &#39;show_data.html&#39;, {}) # @login_required def user_html(request): return render(request, &#39;user.html&#39;, {}) # @login_required def test_html(request): return render(request, &#39;test.html&#39;, {}) # @login_required def detection_html(request): return render(request, &#39;detection.html&#39;, {}) # @login_required def detection_CB_html(request): return render(request, &#39;detection_CB.html&#39;, {}) # @login_required def detection_video_html(request): return render(request, &#39;detection_video.html&#39;, {}) # @login_required def sjdsjksjskfs_html(request): return render(request, &#39;sjdsjksjskfs.html&#39;, {}) # @login_required def upload_video(request): if request.method == &#39;POST&#39;: try: video_file = request.FILES.get(&#39;video&#39;) video_id = request.POST.get(&#39;video_id&#39;) if not video_file or not video_id: return JsonResponse({&#39;status&#39;: &#39;error&#39;, &#39;message&#39;: &#39;缺少参数&#39;}) # 确保临时目录存在 temp_dir = os.path.join(settings.BASE_DIR, &#39;temp&#39;, &#39;videos&#39;) if not os.path.exists(temp_dir): os.makedirs(temp_dir) # 保存视频文件 video_path = os.path.join(temp_dir, f"{video_id}.mp4") with open(video_path, &#39;wb+&#39;) as destination: for chunk in video_file.chunks(): destination.write(chunk) return JsonResponse({&#39;status&#39;: &#39;success&#39;, &#39;video_id&#39;: video_id}) except Exception as e: return JsonResponse({&#39;status&#39;: &#39;error&#39;, &#39;message&#39;: str(e)}) return JsonResponse({&#39;status&#39;: &#39;error&#39;, &#39;message&#39;: &#39;无效请求&#39;}, status=405) @csrf_exempt def detect_video(request): if request.method == &#39;POST&#39;: # 获取视频文件 video_file = request.FILES.get(&#39;video&#39;) if video_file: # 保存视频文件到临时目录 video_path = os.path.join(&#39;temp&#39;, video_file.name) with open(video_path, &#39;wb+&#39;) as destination: for chunk in video_file.chunks(): destination.write(chunk) # 模型路径 model_path = os.path.join(settings.BASE_DIR, "Behaviewer/models/best.pt") # 输出视频路径 output_video_dir = os.path.join(settings.MEDIA_ROOT, &#39;videos&#39;) if not os.path.exists(output_video_dir): os.makedirs(output_video_dir) output_video_path = os.path.join(output_video_dir, video_file.name) # 调用函数进行视频目标检测 detect_objects_in_video(model_path, video_path, output_video_path, show=False) # 删除临时视频文件 os.remove(video_path) # 返回检测好的视频文件的路径 output_video_url = f&#39;{settings.MEDIA_URL}videos/{os.path.basename(output_video_path)}&#39; return JsonResponse({&#39;success&#39;: True, &#39;output_video_url&#39;: output_video_url}) else: return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: &#39;未找到视频文件&#39;}) else: return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: &#39;只支持POST请求&#39;}) # 错步页面模型调用检测 def detect_objects_in_video(model_path, video_path, output_path=None, show=True): # 加载预训练模型 model = YOLO(model_path) # 打开视频文件 cap = cv2.VideoCapture(video_path) # 获取视频的帧率、宽度高度 fps = cap.get(cv2.CAP_PROP_FPS) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 如果指定了输出路径,创建视频写入对象 if output_path: fourcc = cv2.VideoWriter_fourcc(*&#39;mp4v&#39;) out = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) frame_count = 0 total_time = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 记录开始时间 start_time = time.time() # 进行目标检测 results = model(frame) # 记录结束时间并累加耗时 end_time = time.time() total_time += end_time - start_time frame_count += 1 # 获取检测结果并绘制到帧上 annotated_frame = results[0].plot() # 计算并显示FPS fps_current = 1 / (end_time - start_time) cv2.putText(annotated_frame, f"FPS: {fps_current:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 保存帧到输出视频 if output_path: out.write(annotated_frame) # 显示结果 if show: cv2.imshow("Object Detection", annotated_frame) if cv2.waitKey(1) & 0xFF == ord(&#39;q&#39;): break # 释放资源 cap.release() if output_path: out.release() cv2.destroyAllWindows() # 计算平均FPS if frame_count > 0: avg_fps = frame_count / total_time print(f"处理完成! 平均FPS: {avg_fps:.2f}") print(f"总帧数: {frame_count}") print(f"总耗时: {total_time:.2f}秒") #模态框 #框选目标 #deepseek版 # @csrf_exempt # def detect_target(request): # if request.method == &#39;POST&#39;: # try: # # 获取POST数据 # data = json.loads(request.body) # image_data = data[&#39;image&#39;] # roi_data = data[&#39;roi&#39;] # # # 从Base64提取图像数据 # header, encoded = image_data.split(",", 1) # image_bytes = base64.b64decode(encoded) # nparr = np.frombuffer(image_bytes, np.uint8) # frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # # # 准备配置区域(根据ROI) # x, y, w, h = roi_data[&#39;x&#39;], roi_data[&#39;y&#39;], roi_data[&#39;width&#39;], roi_data[&#39;height&#39;] # points = [[x, y], [x + w, y], [x + w, y + h], [x, y + h]] # # # 配置检测区域(格式要求与page_4_1_auto_set.py一致) # config_area_current = {&#39;观察区1&#39;: [[points]]} # # # 调用检测算法(使用默认参数) # processed_frame, mean_value = image_detect( # frame, # config_area_current, # currentback=0, # 0=检测比背景暗的目标 # kernal_erode=1, # kernal_dilate=1, # kernal_erode_2=1, # min_area=1, # max_area=10000, # adjust_threshold=15 # ) # # # 将处理后的图像转换为Base64 # _, buffer = cv2.imencode(&#39;.jpg&#39;, processed_frame) # processed_image_base64 = base64.b64encode(buffer).decode(&#39;utf-8&#39;) # # return JsonResponse({ # &#39;success&#39;: True, # &#39;processed_image&#39;: processed_image_base64, # &#39;mean_value&#39;: mean_value # }) # except Exception as e: # return JsonResponse({ # &#39;success&#39;: False, # &#39;message&#39;: str(e) # }) # return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: &#39;Invalid request&#39;}) @csrf_exempt def detect_target(request): if request.method == &#39;POST&#39;: try: # 获取POST数据 data = json.loads(request.body) image_data = data[&#39;image&#39;] roi_data = data[&#39;roi&#39;] params = data.get(&#39;params&#39;, {}) # 从Base64提取图像数据 header, encoded = image_data.split(",", 1) image_bytes = base64.b64decode(encoded) nparr = np.frombuffer(image_bytes, np.uint8) frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # 准备配置区域(根据ROI) x, y, w, h = roi_data[&#39;x&#39;], roi_data[&#39;y&#39;], roi_data[&#39;width&#39;], roi_data[&#39;height&#39;] points = [[x, y], [x + w, y], [x + w, y + h], [x, y + h]] # 配置检测区域 config_area_current = {&#39;观察区1&#39;: [[points]]} # 调用检测算法 processed_frame, mean_value = image_detect( frame, config_area_current, currentback=params.get(&#39;currentback&#39;, 0), kernal_erode=params.get(&#39;kernal_erode&#39;, 1), kernal_dilate=params.get(&#39;kernal_dilate&#39;, 1), kernal_erode_2=params.get(&#39;kernal_erode_2&#39;, 1), min_area=params.get(&#39;min_area&#39;, 1), max_area=params.get(&#39;max_area&#39;, 10000), adjust_threshold=params.get(&#39;adjust_threshold&#39;, 15) ) # 将处理后的图像转换为Base64 _, buffer = cv2.imencode(&#39;.jpg&#39;, processed_frame) processed_image_base64 = base64.b64encode(buffer).decode(&#39;utf-8&#39;) return JsonResponse({ &#39;success&#39;: True, &#39;processed_image&#39;: processed_image_base64, &#39;mean_value&#39;: mean_value }) except Exception as e: return JsonResponse({ &#39;success&#39;: False, &#39;message&#39;: str(e) }) return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: &#39;Invalid request&#39;}) # 添加新的视频处理视图 @csrf_exempt def process_video_stream(request): if request.method == &#39;POST&#39;: try: data = json.loads(request.body) video_id = data[&#39;video_id&#39;] roi_data = data[&#39;roi&#39;] params = data.get(&#39;params&#39;, {}) # 获取视频路径 video_path = os.path.join(settings.BASE_DIR, &#39;temp&#39;, &#39;videos&#39;, f"{video_id}.mp4") if not os.path.exists(video_path): return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: &#39;Video file not found&#39;}) # 准备ROI配置 x, y, w, h = roi_data[&#39;x&#39;], roi_data[&#39;y&#39;], roi_data[&#39;width&#39;], roi_data[&#39;height&#39;] points = [[x, y], [x + w, y], [x + w, y + h], [x, y + h]] config_area = {&#39;观察区&#39;: [[points]]} # 创建流式响应 response = StreamingHttpResponse( video_processing_generator(video_path, config_area, params), content_type=&#39;multipart/x-mixed-replace; boundary=frame&#39; ) return response except Exception as e: return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: str(e)}) return JsonResponse({&#39;success&#39;: False, &#39;message&#39;: &#39;Invalid request method&#39;}) # 视频处理生成器 def video_processing_generator(video_path, config_area, params): cap = cv2.VideoCapture(video_path) # 获取视频信息 fps = cap.get(cv2.CAP_PROP_FPS) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) while cap.isOpened(): ret, frame = cap.read() if not ret: break # 处理当前帧 processed_frame, _ = image_detect( frame, config_area, currentback=params.get(&#39;currentback&#39;, 0), kernal_erode=params.get(&#39;kernal_erode&#39;, 1), kernal_dilate=params.get(&#39;kernal_dilate&#39;, 1), kernal_erode_2=params.get(&#39;kernal_erode_2&#39;, 1), min_area=params.get(&#39;min_area&#39;, 1), max_area=params.get(&#39;max_area&#39;, 10000), adjust_threshold=params.get(&#39;adjust_threshold&#39;, 15) ) # 转换为JPEG格式 _, buffer = cv2.imencode(&#39;.jpg&#39;, processed_frame) frame_data = buffer.tobytes() # 以MJPEG格式发送帧 yield (b&#39;--frame\r\n&#39; b&#39;Content-Type: image/jpeg\r\n\r\n&#39; + frame_data + b&#39;\r\n&#39;) cap.release() 报错2025-07-30 11:30:09,399 WARNING D:\anaconda\envs\All\lib\site-packages\django\http\response.py:517: builtins.Warning: StreamingHttpResponse must consume synchronous iterators in order to serve them asynchronously. Use an asynchronous iterator instead
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值