添加不使用Redis配置

This commit is contained in:
liurui 2025-11-02 13:00:04 +08:00
parent f3ede6cb19
commit 8ad03fcbf2
14 changed files with 10174 additions and 53 deletions

26
QUICK_FIX.bat Normal file
View File

@ -0,0 +1,26 @@
@echo off
echo ============================================================
echo Fixing Redis Cache UTF-8 Decode Error
echo ============================================================
echo.
echo Step 1: Flushing Redis database 1...
redis-cli -n 1 FLUSHDB
echo Done!
echo.
echo Step 2: Clearing Django cache...
python manage.py clear_cache
echo Done!
echo.
echo Step 3: Reinitializing system config...
python fix_cache.py
echo Done!
echo.
echo ============================================================
echo Cache fixed! Now restart your Django server:
echo python manage.py runserver
echo ============================================================
pause

View File

@ -5,7 +5,41 @@ from django.db import connection
from django.core.cache import cache
from dvadmin.utils.validator import CustomValidationError
dispatch_db_type = getattr(settings, 'DISPATCH_DB_TYPE', 'redis') # redis
# 检查是否使用Redis
try:
from conf.env import USE_REDIS
except ImportError:
USE_REDIS = getattr(settings, 'USE_REDIS', False)
dispatch_db_type = getattr(settings, 'DISPATCH_DB_TYPE', 'redis' if USE_REDIS else 'database') # 根据USE_REDIS自动选择
def _delete_corrupted_cache_key(key):
"""
Delete a corrupted cache key using raw Redis client to bypass Django cache decode
"""
if not USE_REDIS:
# 如果不是使用Redis直接使用cache.delete
cache.delete(key)
return True
try:
import redis
from conf.env import REDIS_HOST, REDIS_PASSWORD, REDIS_DB
if REDIS_PASSWORD:
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, password=REDIS_PASSWORD)
else:
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB)
# Use raw Redis delete to bypass Django's cache layer
# Django adds a prefix, try both with and without
deleted = r.delete(key)
deleted += r.delete(f":1:{key}") # Django cache with version prefix
print(f"Deleted {deleted} corrupted cache key(s) for: {key}")
return True
except Exception as e:
print(f"Error deleting corrupted key {key}: {e}")
return False
def is_tenants_mode():
@ -157,10 +191,20 @@ def get_dictionary_config(schema_name=None):
:return:
"""
if dispatch_db_type == 'redis':
init_dictionary_data = cache.get(f"init_dictionary")
if not init_dictionary_data:
try:
init_dictionary_data = cache.get(f"init_dictionary")
if not init_dictionary_data:
refresh_dictionary()
return cache.get(f"init_dictionary") or {}
except (UnicodeDecodeError, Exception) as e:
# Handle corrupted cache data - delete using raw Redis and refresh
print(f"Cache decode error, clearing corrupted key: {e}")
_delete_corrupted_cache_key("init_dictionary")
refresh_dictionary()
return cache.get(f"init_dictionary") or {}
try:
return cache.get(f"init_dictionary") or {}
except:
return {}
if not settings.DICTIONARY_CONFIG:
refresh_dictionary()
if is_tenants_mode():
@ -178,11 +222,22 @@ def get_dictionary_values(key, schema_name=None):
:return:
"""
if dispatch_db_type == 'redis':
dictionary_config = cache.get(f"init_dictionary")
if not dictionary_config:
refresh_dictionary()
try:
dictionary_config = cache.get(f"init_dictionary")
return dictionary_config.get(key)
if not dictionary_config:
refresh_dictionary()
dictionary_config = cache.get(f"init_dictionary")
return dictionary_config.get(key)
except (UnicodeDecodeError, Exception) as e:
# Handle corrupted cache data - delete using raw Redis and refresh
print(f"Cache decode error, clearing corrupted key: {e}")
_delete_corrupted_cache_key("init_dictionary")
refresh_dictionary()
try:
dictionary_config = cache.get(f"init_dictionary")
return dictionary_config.get(key) if dictionary_config else None
except:
return None
dictionary_config = get_dictionary_config(schema_name)
return dictionary_config.get(key)
@ -214,10 +269,20 @@ def get_system_config(schema_name=None):
:return:
"""
if dispatch_db_type == 'redis':
init_dictionary_data = cache.get(f"init_system_config")
if not init_dictionary_data:
try:
init_dictionary_data = cache.get(f"init_system_config")
if not init_dictionary_data:
refresh_system_config()
return cache.get(f"init_system_config") or {}
except (UnicodeDecodeError, Exception) as e:
# Handle corrupted cache data - delete using raw Redis and refresh
print(f"Cache decode error, clearing corrupted key: {e}")
_delete_corrupted_cache_key("init_system_config")
refresh_system_config()
return cache.get(f"init_system_config") or {}
try:
return cache.get(f"init_system_config") or {}
except:
return {}
if not settings.SYSTEM_CONFIG:
refresh_system_config()
if is_tenants_mode():
@ -235,11 +300,22 @@ def get_system_config_values(key, schema_name=None):
:return:
"""
if dispatch_db_type == 'redis':
system_config = cache.get(f"init_system_config")
if not system_config:
refresh_system_config()
try:
system_config = cache.get(f"init_system_config")
return system_config.get(key)
if not system_config:
refresh_system_config()
system_config = cache.get(f"init_system_config")
return system_config.get(key)
except (UnicodeDecodeError, Exception) as e:
# Handle corrupted cache data - delete using raw Redis and refresh
print(f"Cache decode error, clearing corrupted key: {e}")
_delete_corrupted_cache_key("init_system_config")
refresh_system_config()
try:
system_config = cache.get(f"init_system_config")
return system_config.get(key) if system_config else None
except:
return None
system_config = get_system_config(schema_name)
return system_config.get(key)

View File

@ -175,27 +175,39 @@ STATICFILES_FINDERS = (
# ================================================= #
# ******************* Redis缓存配置 ******************* #
# ================================================= #
# 根据是否有密码决定Redis URL格式
if REDIS_PASSWORD:
REDIS_CACHE_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
else:
REDIS_CACHE_URL = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
# 是否使用Redis如果不使用Redis则使用本地内存缓存
USE_REDIS = getattr(locals(), "USE_REDIS", False)
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": REDIS_CACHE_URL,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 100,
"decode_responses": True
},
"SOCKET_CONNECT_TIMEOUT": 5, # 连接超时时间(秒)
"SOCKET_TIMEOUT": 5, # 读写超时时间(秒)
if USE_REDIS:
# 使用Redis缓存
if REDIS_PASSWORD:
REDIS_CACHE_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
else:
REDIS_CACHE_URL = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": REDIS_CACHE_URL,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 100,
"decode_responses": True
},
"SOCKET_CONNECT_TIMEOUT": 5, # 连接超时时间(秒)
"SOCKET_TIMEOUT": 5, # 读写超时时间(秒)
}
}
}
else:
# 使用本地内存缓存不使用Redis
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
"LOCATION": "unique-snowflake",
}
}
}
# ================================================= #
# ******************* 跨域的配置 ******************* #
@ -214,21 +226,26 @@ CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持
# ********************* channels配置 ******************* #
# ===================================================== #
ASGI_APPLICATION = 'application.asgi.application'
# CHANNEL_LAYERS = {
# "default": {
# "BACKEND": "channels.layers.InMemoryChannelLayer"
# }
# }
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [(f'{REDIS_HOST}', 6379)],
"password": REDIS_PASSWORD if REDIS_PASSWORD else None,
"db": REDIS_DB,
# 根据是否使用Redis选择channel layer
if USE_REDIS:
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [(f'{REDIS_HOST}', 6379)],
"password": REDIS_PASSWORD if REDIS_PASSWORD else None,
"db": REDIS_DB,
},
},
},
}
}
else:
# 不使用Redis使用内存channel layer
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
# ================================================= #
@ -418,13 +435,23 @@ API_MODEL_MAP = {
DJANGO_CELERY_BEAT_TZ_AWARE = False
CELERY_TIMEZONE = "Asia/Shanghai" # celery 时区问题
# Celery配置 - 使用Redis作为broker和result backend
if REDIS_PASSWORD:
CELERY_BROKER_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
CELERY_RESULT_BACKEND = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
# Celery配置 - 根据是否使用Redis选择broker和result backend
if USE_REDIS:
# 使用Redis作为broker和result backend
if REDIS_PASSWORD:
CELERY_BROKER_URL = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
CELERY_RESULT_BACKEND = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:6379/{REDIS_DB}"
else:
CELERY_BROKER_URL = f"redis://{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
else:
CELERY_BROKER_URL = f"redis://{REDIS_HOST}:6379/{CELERY_BROKER_DB}"
CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:6379/{REDIS_DB}"
# 不使用Redis使用Dummy brokerCelery将不会真正运行任务
# 如果需要真正的异步任务请安装并配置RabbitMQ或使用数据库作为broker
CELERY_BROKER_URL = "amqp://guest@localhost//" # 需要RabbitMQ如果没有则使用dummy
CELERY_RESULT_BACKEND = "cache+memory://" # 使用内存存储结果
# 注意如果没有RabbitMQCelery任务将不会真正执行
# 可以使用数据库作为brokerCELERY_BROKER_URL = "db+sqlite:///celery_broker.sqlite"
# 但这需要安装kombu[db]或kombu[sqlalchemy]
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

67
check_db.py Normal file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Check database for SystemConfig issues
"""
import os
import sys
import django
# Setup Django environment
sys.path.insert(0, os.path.dirname(__file__))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
django.setup()
from dvadmin.system.models import SystemConfig
print("=" * 60)
print("Checking SystemConfig Database")
print("=" * 60)
try:
# Check if table exists and has data
count = SystemConfig.objects.count()
print(f"\n✓ SystemConfig table exists")
print(f"✓ Found {count} records")
if count == 0:
print("\n⚠ WARNING: No system config records found!")
print(" You may need to run: python manage.py init")
else:
# Check for problematic records
print("\nChecking for problematic records...")
configs = SystemConfig.objects.filter(parent_id__isnull=False).values(
'id', 'parent__key', 'key', 'value', 'form_item_type'
)[:10]
print(f"\nFirst 10 config records:")
for config in configs:
key_name = f"{config.get('parent__key')}.{config.get('key')}"
value = config.get('value')
print(f" - {key_name}: {type(value).__name__} = {str(value)[:50]}...")
# Try to build the config dict like dispatch does
print("\n" + "=" * 60)
print("Testing config building (like dispatch.py does)...")
print("=" * 60)
from application.dispatch import _get_all_system_config
try:
data = _get_all_system_config()
print(f"\n✓ Successfully built config dict with {len(data)} keys")
print("\nSample keys:")
for i, (k, v) in enumerate(list(data.items())[:5]):
print(f" - {k}: {type(v).__name__}")
if i >= 4:
break
except Exception as e:
print(f"\n✗ ERROR building config: {e}")
import traceback
traceback.print_exc()
except Exception as e:
print(f"\n✗ ERROR: {e}")
import traceback
traceback.print_exc()
print("\n" + "=" * 60)

View File

@ -28,6 +28,10 @@ TABLE_PREFIX = "dvadmin_"
# ================================================= #
# ******** redis配置无redis 可不进行配置 ******** #
# ================================================= #
# 是否使用Redis设置为False则不使用Redis使用本地内存缓存和数据库
USE_REDIS = False
# 以下Redis配置仅在USE_REDIS=True时生效
REDIS_DB = 1
CELERY_BROKER_DB = 3
REDIS_PASSWORD = 'DVADMIN3'

View File

@ -28,6 +28,10 @@ TABLE_PREFIX = "dvadmin_"
# ================================================= #
# ******** redis配置无redis 可不进行配置 ******** #
# ================================================= #
# 是否使用Redis设置为False则不使用Redis使用本地内存缓存和数据库
USE_REDIS = False
# 以下Redis配置仅在USE_REDIS=True时生效
REDIS_DB = 1
CELERY_BROKER_DB = 3
REDIS_PASSWORD = '' # 无密码的Redis服务器

Binary file not shown.

View File

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
"""
Clear Django cache to fix UTF-8 decode errors
"""
from django.core.management.base import BaseCommand
from django.core.cache import cache
class Command(BaseCommand):
help = 'Clear Django cache (useful for fixing UTF-8 decode errors)'
def handle(self, *args, **options):
try:
cache.clear()
self.stdout.write(self.style.SUCCESS('Successfully cleared cache!'))
except Exception as e:
self.stdout.write(self.style.ERROR(f'Failed to clear cache: {e}'))

112
fix_cache.py Normal file
View File

@ -0,0 +1,112 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Fix corrupted Redis cache by deleting specific keys
"""
import os
import sys
import django
# Setup Django environment
sys.path.insert(0, os.path.dirname(__file__))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
django.setup()
import redis
from conf.env import REDIS_HOST, REDIS_PASSWORD, REDIS_DB
def fix_cache():
"""Delete corrupted cache keys"""
try:
# Create Redis connection
if REDIS_PASSWORD:
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, password=REDIS_PASSWORD)
else:
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB)
print("=" * 60)
print("Fixing corrupted Redis cache...")
print("=" * 60)
# List of keys that might be corrupted
problem_keys = [
'init_system_config',
'init_dictionary',
':1:init_system_config',
':1:init_dictionary',
]
deleted_count = 0
for key in problem_keys:
try:
# Try to get the key
exists = r.exists(key)
if exists:
print(f"\n✓ Found key: {key}")
# Try to decode it
try:
value = r.get(key)
if value:
# Try to decode as UTF-8
value.decode('utf-8')
print(f" → Key is OK (can be decoded)")
except UnicodeDecodeError:
print(f" → Key is CORRUPTED (UTF-8 decode error)")
r.delete(key)
print(f" → DELETED corrupted key")
deleted_count += 1
except Exception as e:
print(f" → Error checking key: {e}")
r.delete(key)
print(f" → DELETED problematic key")
deleted_count += 1
except Exception as e:
print(f"✗ Error processing key {key}: {e}")
# Also clear all keys with pattern
print("\n" + "=" * 60)
print("Searching for all cache keys...")
all_keys = r.keys('*')
print(f"Found {len(all_keys)} total keys in Redis DB {REDIS_DB}")
if all_keys:
print("\nChecking all keys for corruption...")
for key in all_keys:
try:
key_str = key.decode('utf-8') if isinstance(key, bytes) else key
value = r.get(key)
if value:
try:
value.decode('utf-8')
except UnicodeDecodeError:
print(f" → Corrupted key found: {key_str}")
r.delete(key)
deleted_count += 1
print(f" → DELETED")
except Exception as e:
print(f" → Error with key: {e}")
print("\n" + "=" * 60)
print(f"✓ Fixed! Deleted {deleted_count} corrupted keys")
print("=" * 60)
# Now reinitialize the cache
print("\nReinitializing system config...")
from application import dispatch
dispatch.refresh_system_config()
dispatch.refresh_dictionary()
print("✓ System config reinitialized!")
return True
except redis.ConnectionError as e:
print(f"✗ Redis connection failed: {e}")
print(" Make sure Redis server is running")
return False
except Exception as e:
print(f"✗ Error: {e}")
import traceback
traceback.print_exc()
return False
if __name__ == '__main__':
fix_cache()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

79
test_redis.py Normal file
View File

@ -0,0 +1,79 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Test Redis connection and clear cache if needed
"""
import os
import sys
import django
# Setup Django environment
sys.path.insert(0, os.path.dirname(__file__))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
django.setup()
from django.core.cache import cache
import redis
def test_redis_connection():
"""Test if Redis is accessible"""
try:
from conf.env import REDIS_HOST, REDIS_PASSWORD, REDIS_DB
# Create Redis connection
if REDIS_PASSWORD:
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, password=REDIS_PASSWORD, decode_responses=True)
else:
r = redis.Redis(host=REDIS_HOST, port=6379, db=REDIS_DB, decode_responses=True)
# Test connection
response = r.ping()
print(f"✓ Redis connection successful: {response}")
# Get all keys
keys = r.keys('*')
print(f"✓ Found {len(keys)} keys in Redis database {REDIS_DB}")
if keys:
print("\nKeys in Redis:")
for key in keys[:10]: # Show first 10 keys
print(f" - {key}")
if len(keys) > 10:
print(f" ... and {len(keys) - 10} more")
return True
except redis.ConnectionError as e:
print(f"✗ Redis connection failed: {e}")
print(" Make sure Redis server is running: redis-server")
return False
except Exception as e:
print(f"✗ Error: {e}")
return False
def clear_django_cache():
"""Clear Django cache"""
try:
cache.clear()
print("\n✓ Django cache cleared successfully!")
return True
except Exception as e:
print(f"\n✗ Failed to clear Django cache: {e}")
return False
if __name__ == '__main__':
print("=" * 60)
print("Redis Connection Test & Cache Clear Utility")
print("=" * 60)
if test_redis_connection():
print("\n" + "=" * 60)
choice = input("\nDo you want to clear the Django cache? (y/n): ").lower()
if choice == 'y':
clear_django_cache()
else:
print("Cache not cleared.")
else:
print("\n⚠ Cannot clear cache - Redis connection failed")
print("Please start Redis server first: redis-server")
print("\n" + "=" * 60)

View File

@ -0,0 +1,150 @@
# 不使用Redis的配置说明
## 概述
本项目支持两种运行模式:
1. **使用Redis模式** - 生产环境推荐,提供分布式缓存和更好的性能
2. **不使用Redis模式** - 开发/测试环境推荐使用本地内存缓存无需安装Redis
## 配置方式
### 不使用Redis配置
`conf/env.py` 文件中,将 `USE_REDIS` 设置为 `False`
```python
# ================================================= #
# ******** redis配置无redis 可不进行配置 ******** #
# ================================================= #
# 是否使用Redis设置为False则不使用Redis使用本地内存缓存和数据库
USE_REDIS = False # 设置为False
# 以下Redis配置仅在USE_REDIS=True时生效
REDIS_DB = 1
CELERY_BROKER_DB = 3
REDIS_PASSWORD = ''
REDIS_HOST = '127.0.0.1'
```
### 使用Redis配置
如果需要使用Redis`USE_REDIS` 设置为 `True`
```python
USE_REDIS = True # 设置为True
# 配置Redis连接信息
REDIS_DB = 1
CELERY_BROKER_DB = 3
REDIS_PASSWORD = 'your_password' # Redis密码无密码则留空
REDIS_HOST = '127.0.0.1' # Redis服务器地址
```
## 不同配置下的行为
### 1. 缓存系统
| 配置 | 缓存后端 | 说明 |
|------|---------|------|
| `USE_REDIS = False` | `django.core.cache.backends.locmem.LocMemCache` | 本地内存缓存 |
| `USE_REDIS = True` | `django_redis.cache.RedisCache` | Redis分布式缓存 |
**注意**:本地内存缓存在多进程部署环境下不共享,重启后数据会丢失。
### 2. ChannelsWebSocket/SSE
| 配置 | Channel Layer | 说明 |
|------|--------------|------|
| `USE_REDIS = False` | `channels.layers.InMemoryChannelLayer` | 内存通道层 |
| `USE_REDIS = True` | `channels_redis.core.RedisChannelLayer` | Redis通道层 |
**注意**:内存通道层在多实例部署环境下不支持跨实例通信。
### 3. Celery异步任务
| 配置 | Broker | Result Backend | 说明 |
|------|--------|---------------|------|
| `USE_REDIS = False` | `amqp://guest@localhost//` | `cache+memory://` | 需要RabbitMQ |
| `USE_REDIS = True` | `redis://...` | `redis://...` | Redis作为broker和backend |
**注意**
- 不使用Redis时Celery需要RabbitMQ作为broker
- 如果项目不使用Celery异步任务可以忽略此配置
- 可以使用数据库作为broker需要额外配置
### 4. 系统配置和字典缓存
| 配置 | 存储方式 | 说明 |
|------|---------|------|
| `USE_REDIS = False` | 从数据库读取 | 每次查询数据库 |
| `USE_REDIS = True` | Redis缓存 | 首次查询后缓存到Redis |
## 部署建议
### 开发/测试环境
```python
USE_REDIS = False # 推荐,简化环境配置
```
### 单机生产环境
```python
USE_REDIS = False # 可接受但建议使用Redis以提高性能
```
### 多实例/分布式生产环境
```python
USE_REDIS = True # 必需,确保多实例间数据共享
```
## 性能对比
| 场景 | 不使用Redis | 使用Redis |
|------|-----------|----------|
| 缓存查询速度 | 快(内存) | 快(内存+网络) |
| 多实例数据共享 | ❌ 不支持 | ✅ 支持 |
| 缓存持久化 | ❌ 不支持 | ✅ 支持(可配置) |
| 部署复杂度 | ✅ 简单 | ⚠️ 需要部署Redis |
| 成本 | ✅ 免费 | ⚠️ 需要服务器资源 |
## 切换配置
1. 修改 `conf/env.py` 中的 `USE_REDIS` 配置
2. 重启Django服务
3. 如果从Redis切换到非Redis建议清理之前的Redis缓存
## 故障排查
### 问题项目启动报错提示Redis连接失败
**解决方案**
- 检查 `USE_REDIS` 是否正确设置为 `False`
- 确认 `conf/env.py` 文件已保存
### 问题:多用户环境下缓存不同步
**解决方案**
- 如果在多实例部署环境必须使用Redis
- 将 `USE_REDIS` 设置为 `True` 并配置Redis服务器
### 问题Celery任务无法执行
**解决方案**
- 检查是否安装了RabbitMQ或Redis
- 确认Celery worker是否正在运行
- 不使用异步任务时可以忽略Celery相关配置
## 相关文件
- `conf/env.py` - 环境配置文件
- `conf/env.example.py` - 环境配置示例文件
- `application/settings.py` - Django主配置文件
- `application/dispatch.py` - 缓存相关工具函数
## 依赖说明
不使用Redis时以下依赖仍然需要安装用于其他功能
- `django-redis==5.4.0` - Redis支持库可选依赖
- `channels-redis==4.2.0` - Channels Redis支持可选依赖
- `redis` - Redis客户端库可选依赖
这些依赖只在 `USE_REDIS = True` 时才会被使用。