ValueError:Invalid model reference *,String model references must be of the form app_label.ModelName

本文记录了一次在Django项目中遇到的迁移错误:ValueError:Invalid model reference 'apps.**.**'。文章详细解释了错误原因,并提供了解决方案——删除之前的迁移文件。

刚刚遇到一个蠢问题, 不过即便是蠢问题但是还是没在网上找到正确的解决方法,遂记录下来。

django 在更新迁移文件的时候出现错误:

ValueError: Invalid model reference 'apps.**.**'. String model references must be of the form 'app_label.ModelName'.

这个问题其实很好解决,把之前的迁移文件删除就行。
 

from datetime import datetime, timezone from typing import Optional, Type from sqlmodel import SQLModel, Field from sqlalchemy import Column, Text, DateTime, func import re # 缓存已创建的模型 _conversation_models: dict[str, Type[SQLModel]] = {} def is_valid_table_name(table_name: str) -> bool: """验证表名是否符合安全规范""" return re.match(r'^conversations_\d+$', table_name) is not None def get_conversation_model(user_id: int) -> Type[SQLModel]: """动态创建用户的对话模型 参数: user_id: 用户唯一ID 返回: 动态生成的SQLModel类 """ table_name = f"conversations_{user_id}" # 验证表名安全性 if not is_valid_table_name(table_name): raise ValueError(f"Invalid table name format: {table_name}") # 返回缓存模型(如果已存在) if table_name in _conversation_models: return _conversation_models[table_name] class Conversation(SQLModel, table=True): __tablename__ = table_name id: Optional[int] = Field(default=None, primary_key=True) character_id: int = Field(foreign_key="characters.id") user_message: str = Field(sa_column=Column(Text)) ai_message: str = Field(sa_column=Column(Text)) timestamp: datetime = Field( default_factory=lambda: datetime.now(timezone.utc), sa_column=Column(DateTime(timezone=True), server_default=func.now()) ) # 设置元数据 model_name = f"Conversation_{user_id}" Conversation.__name__ = model_name Conversation.__qualname__ = model_name # 添加到缓存 _conversation_models[table_name] = Conversation return Conversation 这种动态生成的表怎么办
最新发布
11-12
# backend/database.py import re from typing import Optional, Dict from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from sqlalchemy import text # 数据库配置(请替换为你的真实信息) DATABASE_URL = "mysql+asyncmy://root:123456@localhost/ai_roleplay?charset=utf8mb4" # 创建异步引擎 engine = create_async_engine( DATABASE_URL, echo=True, # 调试时可设为 True 查看 SQL 输出 pool_pre_ping=True, max_overflow=10, pool_size=5 ) # 创建异步 Session 工厂 AsyncSessionLocal = sessionmaker( bind=engine, class_=AsyncSession, expire_on_commit=False ) # 工具函数:获取用户专属对话表名 def get_conversation_table_name(user_id: str): # 安全处理 user_id,防止 SQL 注入(仅允许字母数字下划线) safe_id = "".join(c for c in user_id if c.isalnum() or c == "_") return f"conversations_{safe_id}" # 用户表名白名单校验(防止 SQL 注入) def is_valid_table_name(table_name: str) -> bool: return re.match(r'^conversations_[a-zA-Z0-9_]+$', table_name) is not None async def check_users(account: str, password: str): async with AsyncSessionLocal() as db: # 先查询是否存在该账号 result = await db.execute( text("SELECT id, password FROM users WHERE account = :account"), {"account": account} ) row = result.fetchone() if row: user_id, stored_password = row return user_id, stored_password # 如果不存在,插入新用户 await db.execute( text(""" INSERT INTO users (account, password) VALUES (:account, :password) """), {"account": account, "password": password} ) await db.commit() # 获取刚插入的 ID result = await db.execute(text("SELECT LAST_INSERT_ID()")) user_id = result.scalar() # 动态创建专属对话表(注意:表名需安全) table_name = f"conversations_{user_id}" if not is_valid_table_name(table_name): raise ValueError("Invalid user ID for table name") try: await db.execute(text(f""" CREATE TABLE IF NOT EXISTS `{table_name}` ( id INT AUTO_INCREMENT PRIMARY KEY, character_id INT, user_message TEXT, ai_message TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE ) ENGINE=InnoDB CHARSET=utf8mb4; """)) await db.commit() except Exception as e: await db.rollback() raise Exception(f"Failed to create conversation table for user {user_id}: {e}") return user_id, password async def get_all_characters(): async with AsyncSessionLocal() as db: result = await db.execute( text("SELECT * FROM characters ORDER BY name") ) rows = result.fetchall() # 转成字典列表 return [dict(row._mapping) for row in rows] async def save_conversation(user_id: int, character_id: int, user_msg: str, ai_msg: str): async with AsyncSessionLocal() as db: table_name = f"conversations_{user_id}" if not is_valid_table_name(table_name): raise ValueError("Invalid user ID") try: await db.execute( text(f""" INSERT INTO `{table_name}` (character_id, user_message, ai_message) VALUES (:character_id, :user_msg, :ai_msg) """), { "character_id": character_id, "user_msg": user_msg, "ai_msg": ai_msg } ) await db.commit() except Exception as e: await db.rollback() raise Exception(f"[DB] Failed to save conversation for user {user_id}: {e}") async def get_character_by_id(character_id: int): async with AsyncSessionLocal() as db: result = await db.execute( text("SELECT name, trait FROM characters WHERE id = :id"), {"id": character_id} ) row = result.fetchone() if not row: return None return dict(row._mapping) # 返回 {'name': ..., 'trait': ...} 用ORM重构数据库操作
11-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值