# dj_drone **Repository Path**: duans/dj_drone ## Basic Information - **Project Name**: dj_drone - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-07 - **Last Updated**: 2026-05-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 空中快滴小程序项目-数据接口 ## 项目初始化 1. 安装`django` ```shell pip install django ``` 2. 创建`django`项目 ```shell django-admin startproject dj_dorne ``` 3. 创建一个子应用 ```shell py manage.py startapp client ``` 4. 配置项目 > `settings.py` ```python INSTALLED_APPS=[ # 注册子应用 "client" ] # 配置数据库连接参数 DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "drone_db", # 数据库名称 "USER": "root", # 数据库用户名 "PASSWORD": "root", # 数据库密码 "HOST": "localhost", # 数据库主机地址 "PORT": "3306", # 数据库端口号 } } ``` 5. 安装`mysql`数据库连接引擎`mysqlclient` ```shell pip install mysqlclient ``` `mysqlclient`是C语言编写的一个`mysql`的基础链接库, 如果操作系统缺失一些C语言的基础库, 可能会下载失败 ## 根据数据表自动生成模型类 ```shell py manage.py inspectdb > models.py ``` ## 集成`djangorestframework` 简称`DRF`, 是`django`框架的一个插件, 可以帮助开发者快速构建`api`数据接口 ### 安装 ```shell pip install djangorestframework ``` ### 配置 `settings.py` ```python INSTALLED_APPS=[ # 注册DRF "rest_framework", # 注册子应用 "client" ] # DRF配置 REST_FRAMEWORK = { # 配置分页类 "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", # 配置分页大小: 每页显示的数据条目数量 "PAGE_SIZE": 10, } ``` ### 使用步骤 1. 编写数据表模型类的序列化器类 ```python from rest_framework import serializers # 导入数据表模型类 from client.models import Photography, PhotographyClassify # 航拍服务分类序列化器 class PhotographyClassifySerializer(serializers.ModelSerializer): class Meta: # 指定数据表模型类 model = PhotographyClassify # 指定序列化字段 fields = '__all__' # 航拍服务数据表序列化器 class PhotographySerializer(serializers.ModelSerializer): # 关联分类序列化器 classify = PhotographyClassifySerializer() class Meta: # 指定数据表模型类 model = Photography # 指定序列化字段 fields = '__all__' ``` 2. 编写数据接口类 ```python from rest_framework import viewsets,mixins # 导入数据表模型类 from client.models import Photography, PhotographyClassify # 导入序列化器 from client.serializers import PhotographySerializer, PhotographyClassifySerializer # 航拍服务分类数据接口类 # ListModelMixin: 会自动生成list接口方法 class PhotographyClassifyViewSet(viewsets.GenericViewSet,mixins.ListModelMixin): # 指定数据表模型类的查询集 queryset = PhotographyClassify.objects.all() # 指定序列化器 serializer_class = PhotographyClassifySerializer # 禁用分页功能 pagination_class = None # 航拍服务数据接口类 # RetrieveModelMixin: 会自动生成retrieve接口方法 class PhotographyViewSet(viewsets.GenericViewSet,mixins.ListModelMixin,mixins.RetrieveModelMixin): # 指定数据表模型类的查询集 queryset = Photography.objects.all() # 指定序列化器 serializer_class = PhotographySerializer ``` 3. 配置路由 `urls.py` ```python from django.urls import path,include # 导入drf默认路由类 from rest_framework.routers import DefaultRouter # 导入接口类 from . import views # 创建路由对象 router = DefaultRouter() # 注册路由 router.register(r'photography-classify',views.PhotographyClassifyViewSet) router.register(r'photography',views.PhotographyViewSet) urlpatterns = [ path('',include(router.urls)) ] ``` ## djangorestframework-simplejwt ### 下载安装 ```shell pip install djangorestframework-simplejwt ``` ### 配置 > settings.py ```python from datetime import timedelta # djangorestframework-simplejwt 配置 SIMPLE_JWT = { # 访问令牌过期时间 "ACCESS_TOKEN_LIFETIME": timedelta(hours=1), # 刷新令牌过期时间 "REFRESH_TOKEN_LIFETIME": timedelta(days=1), # 加密算法 "ALGORITHM": "HS256" } ``` ### 使用 **生成令牌** ```python # 生成访问令牌(登录凭证)和刷新令牌(用于刷新访问令牌) # user: 当前登录用户对象 def gen_access_token(user): from rest_framework_simplejwt.tokens import RefreshToken # 生成刷新令牌 refresh = RefreshToken.for_user(user) # 返回访问令牌和刷新令牌 return str(refresh.access_token), str(refresh) ``` **解析令牌** ```python from rest_framework_simplejwt.tokens import AccessToken from rest_framework_simplejwt.exceptions import ExpiredTokenError,InvalidToken,AuthenticationFailed # 验证访问令牌 try: # {"user_id":"当前登录用id"} payload = AccessToken(access_token) except ExpiredTokenError: print('令牌过期') except InvalidToken: print('登录凭证不合法') except AuthenticationFailed: print('登录凭证验证失败') ``` ### ## 集成`redis` 1. 下载安装`redis`数据库软件 https://github.com/redis-windows/redis-windows/releases 2. 下载安装`redis`连接引擎(python连接`redis`的一个基础库) ```shell pip install redis ``` 3. 在`django`项目中配置`redis`连接参数 > `settings.py` ```python # 配置redis链接参数 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/0", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } } ``` 4. 通过cache对象操作`redis` ```python from django.core.cache import cache # 写入数据 cache.set('数据名称','数据值','有效期') # 读取数据 cache.get('数据名称') ``` ## `requirements.txt` 作用: 记录项目依赖项, 需要手动生成 ### 方式1 ```shell pip freeze > requirements.txt ``` 缺点: 会将当前运行环境中安装过的所有依赖写入`requirements.txt`, 无论在项目中是否引入过 ### 方式2 使用第三方工具包`pipreqs`, 需要下载安装 #### 安装`pipreqs` ```shell pip install pipreqs ``` #### 生成`requirements.txt` ```shell # --force: 表示强制生成, 可以覆盖之前生成的requirements.txt pipreqs ./ --force ``` ## 日志配置 日志可以记录项目运行情况, 如果项目运行出错, 可以通过分析日志找出出错原因, 及时修正代码. > `settings.py` ```python # 日志配置 LOG_DIR = os.path.join(BASE_DIR, "logs") # 确保日志目录存在 os.makedirs(LOG_DIR, exist_ok=True) LOGGING = { "version": 1, "disable_existing_loggers": False, # 配置日志格式 'formatters': { # 详细格式:日志级别、包含时间、日志级别、模块名、进程/线程ID、具体消息 'verbose': { 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', 'style': '{', # 使用 {} 风格的字符串格式化 }, # 简单格式:只包含时间和具体的日志消息 'simple': { 'format': '{asctime} {levelname} {message}', 'style': '{', }, }, "handlers": { # 文件日志 "file": { "level": "INFO", # 日志级别 "class": "logging.FileHandler", # 日志处理工具 "filename": os.path.join(LOG_DIR, "django.log"), # 日志文件的保存位置 "encoding": "utf-8", # 日志编码格式 'formatter': 'verbose' # 使用上面定义的简单格式 }, # 控制台日志 "console": { "level": "INFO", # 日志级别 "class": "logging.StreamHandler", # 日志处理工具 } }, # 日志记录器配置 "loggers": { # django框架运行日志记录器 "django": { # 日志处理程序 # file: 文件日志 # console: 控制台日志 "handlers": ["file","console"], # 日志级别 "level": "INFO", # 是否传递日志给父记录器 # True: 传递给父记录器 # False: 不传递给父记录器 # 默认值: True "propagate": True, }, } } ``` ### 按照日期对日志进行切割 > `settings.py` ```python import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent # 确保存放日志的文件夹存在 LOG_DIR = os.path.join(BASE_DIR, 'logs') os.makedirs(LOG_DIR, exist_ok=True) LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'INFO', # 核心配置:使用 TimedRotatingFileHandler 按时间切割日志 'class': 'logging.handlers.TimedRotatingFileHandler', 'filename': os.path.join(LOG_DIR, 'django.log'), # 基础日志文件名 'when': 'midnight', # 每天凌晨(午夜)进行切割 'interval': 1, # 间隔1个when单位(即每1天) 'backupCount': 30, # 保留最近30天的日志文件,超出的会自动删除 'encoding': 'utf-8', # 防止中文乱码 }, }, 'loggers': { # django框架运行产生的日志 'django': { 'handlers': ['file'], 'level': 'INFO', # 日志级别 'propagate': True, }, }, } ``` 生产环境多进程下会出现日志写入错误来拿甚至日志丢失的问题 ### 生产环境多进程部署日志方案 如果你的 `Django `项目在生产环境中使用 **`Gunicorn`** 或 **`uWSGI`** 等多进程方式部署,直接使用 `TimedRotatingFileHandler` 可能会出现问题。 **原因**:Python 的 logging 模块是线程安全的,但**不是进程安全的**。在每天凌晨切割日志的那一瞬间,多个进程可能会同时尝试重命名或删除日志文件,导致日志写入错乱,甚至出现部分日志丢失的情况。 **解决方案**: 如果是多进程环境,建议将 `class` 替换为第三方库提供的多进程安全处理器,例如 `ConcurrentLogHandler`: 1. 安装库:`pip install concurrent-log-handler` 2. 修改配置: > `settings.py` ```python import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent # 确保存放日志的文件夹存在 LOG_DIR = os.path.join(BASE_DIR, 'logs') os.makedirs(LOG_DIR, exist_ok=True) LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'INFO', # 替换为多进程安全的Handler 'class': 'cloghandler.ConcurrentRotatingFileHandler', 'filename': os.path.join(LOG_DIR, 'django.log'), # 按大小切割(例如50MB) 'maxBytes': 1024 * 1024 * 50, 'backupCount': 10, 'encoding': 'utf-8', }, }, 'loggers': { # django框架运行产生的日志 'django': { 'handlers': ['file'], 'level': 'INFO', # 日志级别 'propagate': True, }, }, } ``` ### 日志级别 在 Python 的 `logging` 模块中,内置了 5 个标准的日志级别。它们本质上是带有整数值的常量,**数值越大,级别越高,代表的问题越严重**。 按照严重程度**从低到高**排列如下 | 日志级别 | 对应数值 | 适用场景说明 | | :----------- | :------- | :----------------------------------------------------------- | | **DEBUG** | 10 | **调试信息**。非常详细的诊断信息,通常包含变量值、执行步骤等,仅在开发和排查问题时开启。 | | **INFO** | 20 | **一般信息**。证明程序按预期运行,例如程序启动、关闭、关键操作成功完成等。 | | **WARNING** | 30 | **警告信息**。发生了一些意想不到的事情(如磁盘空间不足),或者预示着将来可能会出现某些问题,但程序目前仍能正常工作。 | | **ERROR** | 40 | **错误信息**。由于发生严重问题,程序的某些功能未能正常执行(如网络请求失败、文件读取异常)。 | | **CRITICAL** | 50 | **严重错误**。发生了极其严重的错误,可能导致程序无法继续运行甚至崩溃(如数据库彻底连不上)。 | ## 微信小程序相关接口 - [微信小程序-登录凭证校验](https://developers.weixin.qq.com/miniprogram/dev/server/API/user-login/api_code2session.html) - [微信小程序-开放数据校验与解密](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html) ### 获取微信用户手机号码 ```html ``` ```jsx // pages/phone/phone.js Page({ getPhoneNumber(event){ // encryptedData: 手机号码加密数据 // iv: 加密向量 const {encryptedData,iv}=event.detail wx.login({ success:(res)=>{ // code: 换取session_key会话令牌的凭证码 const {code}=res // 调用自己的后端接口实现手机号码机密 wx.request({ url:'http://localhost:8000/api/client/wechat/phone_decode/', method:"POST", data:{ encryptedData,iv,code }, success:(result)=>{ console.log(result); } }) } }) }, }) ``` ### 微信一键登录 ```html ``` ```jsx // pages/phone/phone.js Page({ getPhoneNumber(event){ // encryptedData: 手机号码加密数据 // iv: 加密向量 const {encryptedData,iv}=event.detail wx.login({ success:(res)=>{ // code: 换取session_key会话令牌的凭证码 const {code}=res // 调用自己的后端接口实现手机号码机密 wx.request({ url:'http://localhost:8000/api/client/wechat/wechat_login/', method:"POST", data:{ encryptedData,iv,code }, success:(result)=>{ console.log(result); } }) } }) } }) ``` ## 通过`.env`文件保存项目配置信息 1. 下载安装`python-dotenv` ```python pip install python-dotenv ``` 2. 在项目根目录中创建一个`.env`的文件, 将相关配置信息写入该文件 ```python # 环境变量配置文件 # 数据库配置 MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_USER=root MYSQL_PASSWORD=root MYSQL_DATABASE=drone_db # redis配置 REDIS_HOST=localhost REDIS_PORT=6379 REDIS_DB=0 # 微信小程序配置 WECHAT_APPID=wxfa47c341f928dcc5 WECHAT_APPSECRET=900f40d011824a8d3f0fb81fd19bafb5 ``` 3. 在`settings.py`文件中,通过`dotenv.load_dotenv()`将`.env`文件中的配置项载入到环境变量中, 通过`os.getenv()`动态获取环境变量中的配置信息 ```python from dotenv import load_dotenv import os # 加载环境变量: 从.env文件中加载环境变量(django项目的运行内存中) load_dotenv() DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": os.getenv('MYSQL_DATABASE'), # 数据库名称 "USER": os.getenv('MYSQL_USER'), # 数据库用户名 "PASSWORD": os.getenv('MYSQL_PASSWORD'), # 数据库密码 "HOST": os.getenv('MYSQL_HOST'), # 数据库主机地址 "PORT": os.getenv('MYSQL_PORT'), # 数据库端口号 } } # 配置redis链接参数 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": f"redis://{os.getenv('REDIS_HOST')}:{os.getenv('REDIS_PORT')}/{os.getenv('REDIS_DB')}", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } } # 小程序配置信息 WECHAT_APPID=os.getenv('WECHAT_APPID') WECHAT_APPSECRET=os.getenv('WECHAT_APPSECRET') ``` ## 参考文档 - [django官网](https://docs.djangoproject.com/zh-hans/6.0/) - [redis-windows](https://github.com/redis-windows/redis-windows/releases) - [mysql数据库](https://dev.mysql.com/downloads/installer/) - [djangrestframework参考文档](https://www.django-rest-framework.org) - [djangorestframework-simplejwt](https://django-rest-framework-simplejwt.readthedocs.io/en/latest/) - [python-dotenv](https://pypi.org/project/python-dotenv/) - [微信小程序-登录凭证校验](https://developers.weixin.qq.com/miniprogram/dev/server/API/user-login/api_code2session.html) - [微信小程序-开放数据校验与解密](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html)