为什么 Django Admin 模型页面在成功迁移后引发 FieldDoesNotExist 异常?
Why does Django Admin model page raise FieldDoesNotExist exception after a successful migration?
这个让我摸不着头脑。我只是向模型添加了一个新字段。
class Image(BaseModel):
url = models.URLField(max_length=1000, null=True)
content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
# new field added below
class Type(models.TextChoices):
HEADER = 'HEADER', _('Header')
type = models.CharField(
max_length=20,
choices=Type.choices,
null=True,
blank=True
)
class Meta:
db_table = 'Image'
然后我 运行 python manage.py makemigrations
然后是 python manage.py migrate
。这是成功的,我可以在我的数据库中的 table 上看到新字段。来自 django_migrations
table 的信息看起来是正确的。
这是我的迁移文件:
# Generated by Django 3.0.5 on 2022-03-23 12:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('example', '0082_auto_20220322_1937'),
]
operations = [
migrations.AddField(
model_name='image',
name='type',
field=models.CharField(blank=True, choices=[('HEADER', 'Header')], max_length=20, null=True),
),
]
这是我的图像管理文件:
from .base import BaseModelAdmin
class ImageAdmin(BaseModelAdmin):
list_display = ('id', 'url', 'content_type', 'content_object', 'type', 'is_deleted')
list_filter = ('is_deleted',)
这是 ImageAdmin 继承自的 BaseModelAdmin:
from django.contrib.contenttypes.admin import GenericTabularInline
from django.contrib import admin
class BaseModelAdmin(admin.ModelAdmin):
def get_actions(self, request):
actions = super(BaseModelAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
class BaseStackedInline(admin.StackedInline):
def get_actions(self, request):
actions = super(BaseModelAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
class BaseGenericTabularInline(GenericTabularInline):
def get_actions(self, request):
actions = super(BaseModelAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
这里是Image模型继承自的BaseModel:
from django.db import models
class BaseManager(models.Manager):
def get_or_none(self, *args, **kwargs):
try:
return self.get(*args, **kwargs)
except self.model.DoesNotExist:
return None
class BaseModel(models.Model):
is_deleted = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = BaseManager()
def __str__(self):
return F"ID: {self.id}"
class Meta:
abstract = True
我面临的问题是,当我在 django 管理中访问该模型页面时,出现内部服务器错误,内容如下:
Traceback (most recent call last):
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 262, in lookup_field
example_app | f = _get_non_gfk_field(opts, name)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 297, in _get_non_gfk_field
example_app | raise FieldDoesNotExist()
example_app | django.core.exceptions.FieldDoesNotExist
example_app |
example_app | During handling of the above exception, another exception occurred:
example_app |
example_app | Traceback (most recent call last):
example_app | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 34, in inner
example_app | response = get_response(request)
example_app | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 145, in _get_response
example_app | response = self.process_exception_by_middleware(e, request)
example_app | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 143, in _get_response
example_app | response = response.render()
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/response.py", line 105, in render
example_app | self.content = self.rendered_content
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/response.py", line 83, in rendered_content
example_app | return template.render(context, self._request)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/backends/django.py", line 61, in render
example_app | return self.template.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 171, in render
example_app | return self._render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 163, in _render
example_app | return self.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 150, in render
example_app | return compiled_parent._render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 163, in _render
example_app | return self.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 150, in render
example_app | return compiled_parent._render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 163, in _render
example_app | return self.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 62, in render
example_app | result = block.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 62, in render
example_app | result = block.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/base.py", line 33, in render
example_app | return super().render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/library.py", line 214, in render
example_app | _dict = self.func(*resolved_args, **resolved_kwargs)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 342, in result_list
example_app | 'results': list(results(cl)),
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 318, in results
example_app | yield ResultList(None, items_for_result(cl, res, None))
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 309, in __init__
example_app | super().__init__(*items)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 232, in items_for_result
example_app | f, attr, value = lookup_field(field_name, result, cl.model_admin)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 273, in lookup_field
example_app | attr = getattr(obj, name)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/fields.py", line 243, in __get__
example_app | rel_obj = ct.get_object_for_this_type(pk=pk_val)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/models.py", line 175, in get_object_for_this_type
example_app | return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
example_app | AttributeError: 'NoneType' object has no attribute '_base_manager'
我已经多次尝试还原迁移并重新运行它。我也看过其他类似的问题,但 none 的解决方案有效或解决了我的具体问题。
为什么会这样?
我怀疑添加新字段不是问题的原因 - 在您进行此更改的同时出现问题只是巧合。线索在回溯中:
File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/fields.py", line 243, in __get__
rel_obj = ct.get_object_for_this_type(pk=pk_val)
File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/models.py", line 175, in get_object_for_this_type
return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
AttributeError: 'NoneType' object has no attribute '_base_manager'
具体来说,错误来自 contenttypes
框架 - 即,您的 content_type
字段在数据库中至少一个现有模型实例上被破坏。 model_class()
方法返回空值而不是模型 class。
最可能的原因是您删除了之前由您的通用外键引用的模型,或者您从 INSTALLED_APPS
中删除了提供该模型的应用程序。
您应该能够通过 运行 remove_stale_contenttypes
管理命令解决问题。如果这不起作用,那么可能需要手动检查数据库以找出问题所在(清空整个数据库也有助于验证是否是问题所在)。
FieldDoesNotExist
异常不是问题。如果您的内容类型没有问题,它将是 Django properly handled。
旁注:我认为这与您的问题没有任何关系,但使用与 Python built-in functions 冲突的名称不是一个好主意,因为它会导致混淆行为。
这个让我摸不着头脑。我只是向模型添加了一个新字段。
class Image(BaseModel):
url = models.URLField(max_length=1000, null=True)
content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL, null=True)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
# new field added below
class Type(models.TextChoices):
HEADER = 'HEADER', _('Header')
type = models.CharField(
max_length=20,
choices=Type.choices,
null=True,
blank=True
)
class Meta:
db_table = 'Image'
然后我 运行 python manage.py makemigrations
然后是 python manage.py migrate
。这是成功的,我可以在我的数据库中的 table 上看到新字段。来自 django_migrations
table 的信息看起来是正确的。
这是我的迁移文件:
# Generated by Django 3.0.5 on 2022-03-23 12:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('example', '0082_auto_20220322_1937'),
]
operations = [
migrations.AddField(
model_name='image',
name='type',
field=models.CharField(blank=True, choices=[('HEADER', 'Header')], max_length=20, null=True),
),
]
这是我的图像管理文件:
from .base import BaseModelAdmin
class ImageAdmin(BaseModelAdmin):
list_display = ('id', 'url', 'content_type', 'content_object', 'type', 'is_deleted')
list_filter = ('is_deleted',)
这是 ImageAdmin 继承自的 BaseModelAdmin:
from django.contrib.contenttypes.admin import GenericTabularInline
from django.contrib import admin
class BaseModelAdmin(admin.ModelAdmin):
def get_actions(self, request):
actions = super(BaseModelAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
class BaseStackedInline(admin.StackedInline):
def get_actions(self, request):
actions = super(BaseModelAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
class BaseGenericTabularInline(GenericTabularInline):
def get_actions(self, request):
actions = super(BaseModelAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
def has_delete_permission(self, request, obj=None):
return False
这里是Image模型继承自的BaseModel:
from django.db import models
class BaseManager(models.Manager):
def get_or_none(self, *args, **kwargs):
try:
return self.get(*args, **kwargs)
except self.model.DoesNotExist:
return None
class BaseModel(models.Model):
is_deleted = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = BaseManager()
def __str__(self):
return F"ID: {self.id}"
class Meta:
abstract = True
我面临的问题是,当我在 django 管理中访问该模型页面时,出现内部服务器错误,内容如下:
Traceback (most recent call last):
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 262, in lookup_field
example_app | f = _get_non_gfk_field(opts, name)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 297, in _get_non_gfk_field
example_app | raise FieldDoesNotExist()
example_app | django.core.exceptions.FieldDoesNotExist
example_app |
example_app | During handling of the above exception, another exception occurred:
example_app |
example_app | Traceback (most recent call last):
example_app | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 34, in inner
example_app | response = get_response(request)
example_app | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 145, in _get_response
example_app | response = self.process_exception_by_middleware(e, request)
example_app | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 143, in _get_response
example_app | response = response.render()
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/response.py", line 105, in render
example_app | self.content = self.rendered_content
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/response.py", line 83, in rendered_content
example_app | return template.render(context, self._request)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/backends/django.py", line 61, in render
example_app | return self.template.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 171, in render
example_app | return self._render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 163, in _render
example_app | return self.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 150, in render
example_app | return compiled_parent._render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 163, in _render
example_app | return self.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 150, in render
example_app | return compiled_parent._render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 163, in _render
example_app | return self.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 62, in render
example_app | result = block.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 62, in render
example_app | result = block.nodelist.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 936, in render
example_app | bit = node.render_annotated(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 903, in render_annotated
example_app | return self.render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/base.py", line 33, in render
example_app | return super().render(context)
example_app | File "/usr/local/lib/python3.9/site-packages/django/template/library.py", line 214, in render
example_app | _dict = self.func(*resolved_args, **resolved_kwargs)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 342, in result_list
example_app | 'results': list(results(cl)),
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 318, in results
example_app | yield ResultList(None, items_for_result(cl, res, None))
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 309, in __init__
example_app | super().__init__(*items)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/templatetags/admin_list.py", line 232, in items_for_result
example_app | f, attr, value = lookup_field(field_name, result, cl.model_admin)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/admin/utils.py", line 273, in lookup_field
example_app | attr = getattr(obj, name)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/fields.py", line 243, in __get__
example_app | rel_obj = ct.get_object_for_this_type(pk=pk_val)
example_app | File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/models.py", line 175, in get_object_for_this_type
example_app | return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
example_app | AttributeError: 'NoneType' object has no attribute '_base_manager'
我已经多次尝试还原迁移并重新运行它。我也看过其他类似的问题,但 none 的解决方案有效或解决了我的具体问题。
为什么会这样?
我怀疑添加新字段不是问题的原因 - 在您进行此更改的同时出现问题只是巧合。线索在回溯中:
File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/fields.py", line 243, in __get__
rel_obj = ct.get_object_for_this_type(pk=pk_val)
File "/usr/local/lib/python3.9/site-packages/django/contrib/contenttypes/models.py", line 175, in get_object_for_this_type
return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
AttributeError: 'NoneType' object has no attribute '_base_manager'
具体来说,错误来自 contenttypes
框架 - 即,您的 content_type
字段在数据库中至少一个现有模型实例上被破坏。 model_class()
方法返回空值而不是模型 class。
最可能的原因是您删除了之前由您的通用外键引用的模型,或者您从 INSTALLED_APPS
中删除了提供该模型的应用程序。
您应该能够通过 运行 remove_stale_contenttypes
管理命令解决问题。如果这不起作用,那么可能需要手动检查数据库以找出问题所在(清空整个数据库也有助于验证是否是问题所在)。
FieldDoesNotExist
异常不是问题。如果您的内容类型没有问题,它将是 Django properly handled。
旁注:我认为这与您的问题没有任何关系,但使用与 Python built-in functions 冲突的名称不是一个好主意,因为它会导致混淆行为。