Django模型跨两层ForeignKey生成上传路径报错求助
Django中动态设置Lesson模型视频上传路径为courses/课程名/章节名
问题根源
你直接在upload_to里用section.course.name是错误的——定义video字段时,section是ForeignKey字段对象,而非Lesson实例的属性,此时还未创建具体的Lesson对象,自然无法访问关联的Course和Section实例的属性。
正确解决方案:使用upload_to函数
Django的FileField.upload_to支持传入一个自定义函数,该函数会接收两个参数:当前模型的实例(此处为Lesson对象)和上传的文件名,最终返回存储路径。
修改后的完整代码:
from django.db import models from django.utils.text import slugify class Course(models.Model): name = models.CharField(max_length=80) # 其他字段... class Section(models.Model): name = models.CharField(max_length=80) course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='sections') # 其他字段... def lesson_video_upload_path(instance, filename): # 增加空值判断,避免实例未保存时的异常 if instance.section and instance.section.course: # 用slugify处理名称,避免路径出现非法字符(如空格、特殊符号) course_name = slugify(instance.section.course.name) section_name = slugify(instance.section.name) return f'courses/{course_name}/{section_name}/{filename}' # 实例未关联Section时的 fallback 路径 return f'courses/unsaved/{filename}' class Lesson(models.Model): name = models.CharField(max_length=80) section = models.ForeignKey(Section, on_delete=models.CASCADE) video = models.FileField(upload_to=lesson_video_upload_path)
关键说明:
slugify用于标准化名称,将特殊字符、空格替换为连字符,避免文件路径出现非法字符;如果需要保留中文名称,可去掉slugify直接使用原名称(需确保文件系统支持中文路径)。- 空值判断是必要的:当Lesson实例尚未关联Section(比如在admin后台刚创建还未选择Section时),能避免抛出关联对象不存在的异常。
为什么重写__init__会报错
你重写__init__时,在调用父类构造方法之前就访问self.section.id,此时Django模型的内部状态(如_state)尚未初始化,因此会触发'Lesson' object has no attribute '_state'错误。Django模型的初始化逻辑有严格顺序,不要随意在__init__中提前访问实例属性,尤其是关联字段。
内容的提问来源于stack exchange,提问作者iljuhenson
相关产品推荐
相关产品推荐

