在我的应用程序中,我对所有模型都使用一个公共Base
模型。我遇到了无法用Campus
和Hall
模型解释的行为:
class Base(models.Model):
id: int = models.AutoField(primary_key=True, editable=False)
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._initial = self.as_dict
...
@property
def as_dict(self) -> dict:
fields = [field.name for field in self._meta.fields]
res = model_to_dict(self, fields=fields)
return res
...
class Campus(Base):
name: str = models.CharField(max_length=100)
class Meta:
verbose_name_plural = "campuses"
def __str__(self):
return self.name
class Hall(Base):
name: str = models.CharField(max_length=100)
campus: Campus = models.ForeignKey(Campus, on_delete=models.SET_NULL, null=True)
def save(self, *args, **kwargs):
if self.campus is not None and isinstance(self.campus, str):
self.campus = Campus.objects.get_or_create(name=self.campus)[0]
super().save(*args, **kwargs)
def __str__(self):
return f"{self.name}{f' ({self.campus})' if self.campus else ''}"
在管理控制台上,当我试图删除某个Campus
实例时,服务器崩溃。这是(很长)轨迹的一小部分:
Fatal Python error: Cannot recover from stack overflow.
...
Current thread 0x00000bdc (most recent call first):
...
File "P:\Python\Coursist\academic_helper\models\base.py", line 142 in as_dict
File "P:\Python\Coursist\academic_helper\models\base.py", line 98 in __init__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\base.py", line 512 in from_db
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 75 in __iter__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 1261 in _fetch_all
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 258 in __len__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 411 in get
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\base.py", line 627 in refresh_from_db
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query_utils.py", line 139 in __get__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\fields\__init__.py", line 931 in value_from_object
File "C:\Venvs\Coursist\lib\site-packages\django\forms\models.py", line 93 in model_to_dict
File "P:\Python\Coursist\academic_helper\models\base.py", line 142 in as_dict
File "P:\Python\Coursist\academic_helper\models\base.py", line 98 in __init__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\base.py", line 512 in from_db
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 75 in __iter__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 1261 in _fetch_all
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 258 in __len__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 411 in get
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\base.py", line 627 in refresh_from_db
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query_utils.py", line 139 in __get__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\fields\__init__.py", line 931 in value_from_object
File "C:\Venvs\Coursist\lib\site-packages\django\forms\models.py", line 93 in model_to_dict
File "P:\Python\Coursist\academic_helper\models\base.py", line 142 in as_dict
File "P:\Python\Coursist\academic_helper\models\base.py", line 98 in __init__
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\base.py", line 512 in from_db
File "C:\Venvs\Coursist\lib\site-packages\django\db\models\query.py", line 75 in __iter__
...
起初我认为这是Hall
和Campus
之间的某种循环指向问题,但情况似乎并非如此(在调试时,我看不到从Campus
到Hall
的任何指针)。奇怪的是,如果我首先删除所有Hall
实例,那么Campus
的删除就会顺利进行。
我正在使用python 3.7
和Django 3.0.6
BaseModel的设计导致了这个问题,因为
model_to_dict
将解决*到许多关系,并创建可能巨大的列表。管理员创建了自己的内存列表,向您显示了所有要删除的相关模型,这一点被放大了您基本上是在模型的init方法中放置一个序列化表示,您已经将其作为属性。如果这是缓存值的方式,那么我建议您使用
django.utils.functions.cached_property
,并将机制更改为“首次访问时缓存”,而不是“初始化时缓存”:经过一些调试,我提出了以下修补程序:
不确定这是一个优雅/正确的解决方案,但它解决了这个bug,其他一切似乎都很好。
如果还有其他人有更好的想法,我很想听听
相关问题 更多 >
编程相关推荐