You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django同一应用内导入Model报错:无法导入School模型

解决Django模型中ImportError: cannot import name 'School'的问题

这个问题其实是Django模型开发里很常见的顺序依赖+错误导入问题,我帮你一步步理清并解决:

问题根源

你犯了两个小错误:

  1. 多余的内部导入:同一个models.py文件里的模型根本不需要互相导入,你加的from .models import School完全没必要,反而会触发循环导入错误。
  2. 模型定义顺序问题:Python代码是从上到下解析的,你在List模型里引用School时,School的定义还在文件后面,这时候Python还没识别到School这个类,自然会报错。

另外还要注意:你提到School字段可为空,但原代码里没加null=True, blank=True,这个也要补上,否则数据库会强制要求该字段必须有值,不符合你的需求。

两种解决方案

方案1:调整模型定义顺序(最直观)

把School模型移到List模型前面,这样解析到List的school字段时,School已经被定义好了,同时删除多余的导入语句:

from django.db import models
from products.models import Product
from roles.models import User

# Create your models here.
class School(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100, blank=False)
    address_reference = models.CharField(max_length=100, blank=False)
    provincia = models.CharField(max_length=100, blank=False, null=True)
    canton = models.CharField(max_length=100, blank=False, null=True)
    parroquia = models.CharField(max_length=100, blank=False, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return str(self.name)

class List(models.Model):
    LISTA_STATUS = (
        ('recibida_pagada', 'Recibida y pagada'),
        ('recibida_no_pagada', 'Recibida pero no pagada'),
        ('en_revision', 'En revision'),
        ('en_camino', 'En camino'),
        ('entregada', 'Entregada'),
        ('cancelada', 'Cancelada')
    )
    lista_id = models.CharField(max_length=100)
    name = models.CharField(max_length=100)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # 加上null=True和blank=True实现字段可为空
    school = models.OneToOneField(School, on_delete=models.CASCADE, null=True, blank=True)
    status = models.CharField(max_length=20, choices=LISTA_STATUS, default='recibida_pagada')
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return str(self.id)

class ListItem(models.Model):
    lista = models.ForeignKey(List, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    comment = models.CharField(max_length=100, blank=True, null=True, default='')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    step_two_complete = models.BooleanField(default=False)

    def sub_total(self):
        return int(self.product.price)

方案2:使用字符串引用模型(无需调整顺序)

如果你不想改变模型的定义顺序,可以用字符串形式的模型名称来引用,Django会在所有模型加载完成后自动解析这个引用,同样要删除多余导入并补上空字段设置:

from django.db import models
from products.models import Product
from roles.models import User

# Create your models here.
class List(models.Model):
    LISTA_STATUS = (
        ('recibida_pagada', 'Recibida y pagada'),
        ('recibida_no_pagada', 'Recibida pero no pagada'),
        ('en_revision', 'En revision'),
        ('en_camino', 'En camino'),
        ('entregada', 'Entregada'),
        ('cancelada', 'Cancelada')
    )
    lista_id = models.CharField(max_length=100)
    name = models.CharField(max_length=100)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # 用字符串引用School模型,无需提前定义
    school = models.OneToOneField('School', on_delete=models.CASCADE, null=True, blank=True)
    status = models.CharField(max_length=20, choices=LISTA_STATUS, default='recibida_pagada')
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return str(self.id)

class ListItem(models.Model):
    lista = models.ForeignKey(List, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    comment = models.CharField(max_length=100, blank=True, null=True, default='')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    step_two_complete = models.BooleanField(default=False)

    def sub_total(self):
        return int(self.product.price)

class School(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100, blank=False)
    address_reference = models.CharField(max_length=100, blank=False)
    provincia = models.CharField(max_length=100, blank=False, null=True)
    canton = models.CharField(max_length=100, blank=False, null=True)
    parroquia = models.CharField(max_length=100, blank=False, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return str(self.name)

额外提醒

  • 同一个models.py内的模型永远不需要互相导入,Django会自动处理模型间的依赖关系。
  • 字段允许为空时,null=True是数据库层面允许为空,blank=True是表单验证层面允许为空,两者通常需要一起设置。

内容的提问来源于stack exchange,提问作者Omar Gonzales

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 11:27:42