创建或编辑模型实例时 Django admin 404 错误
Django admin 404 error when creating or editing a model instance
我目前正在调试 Django 站点的一个奇怪问题,其中一个特定模型在管理界面中创建新实例或编辑现有实例时触发 404 错误。
具体是提交表单时出现的错误。我可以 GET
改变形式就好了。
这仅在实时站点上发生,并且仅在保存此模型时发生。所有其他模型都按预期运行,当我在本地 运行 时,一切都按预期运行。当以编程方式创建时,无论是在现场还是在本地,一切都很好。
这是我的模型:
class Content(models.Model):
"""Base Content class."""
title = models.CharField(max_length=200)
body = RichTextUploadingField(max_length=30000, blank=True, null=True, config_name='admin')
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
author = models.ForeignKey(to=User, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100, null=True, default=None)
class Meta:
abstract = True
class ContentPage(Content):
"""Represents a page of generic text content."""
title = models.CharField(max_length=200, unique=True)
has_url = models.BooleanField(default=False, help_text='Sets the page to accessible via a URL.')
banner = models.ImageField(upload_to='myfiles/banners/', blank=True, null=True)
def save(self, *args, **kwargs):
"""Create the slug from the title."""
self.slug = slugify(self.title[:100])
super(ContentPage, self).save(*args, **kwargs)
ContentPage
class 是在管理界面中触发问题的原因。我从 Content
继承的另一个 class 工作正常。
我已将我的管理设置剥离为以下内容,但它仍在发生:
class CustomAdminSite(AdminSite):
def get_urls(self):
"""Define custom admin URLs."""
urls = super(CustomAdminSite, self).get_urls()
# Append some new views here...
return urls
admin_site = CustomAdminSite()
admin_site.register(ContentPage)
这是重现问题的基本 URL 配置:
from myapp.admin import admin_site
urlpatterns = [
path('mycooladminsite/', admin_site.urls),
path('', include('myapp.urls')),
]
我检查过的其他一些内容:
- 我没有干扰保存的信号。
- 我没有在模型的
save()
方法中执行任何操作。
- 我已经检查了
get_object_or_404()
个调用,但看不到任何会对此产生影响的调用。
我已经花了几个小时来研究这个问题,但我目前正处于困境。
数据库引擎为mysql.connector.django
,Django 版本为 2.2.11。我无法为该站点更改引擎或将 Django 更新为 3.x。
这是我以前没有注意到的最近的问题。
更新:
我已将问题缩小到 ImageField。当我从显示的字段中删除它时,保存时不会出现问题。
我正在使用自定义管理表单,但这似乎不是问题所在。我已经尝试使用默认值,但它仍然会发生。我一直在寻找存储 class 中的异常,但没有找到任何异常。我一路剥离它,错误仍然存在。
我在 Firefox Developer Tools 中检查了本地 302 POST
和生产 404 POST
,它们几乎相同,但生产服务器是 Apache,x-powered-by
是 Phusion Passenger,而本地服务器是 WSGIServer/0.2 CPython/3.7.3.
我实际上已经注意到 404 与现在生产中的其他 multipart/form-data
表单一起出现,这是我以前从未遇到过的。
我不知道问题是什么,但如果你没有日志,运行 它在产品上使用 DEBUG=False,不要使用 Sentry 等,只有当你保存时才会发生ContentPage
管理表单,然后您可以用
覆盖 ModelAdmin
中的 save_new
或 save_model
方法
def save_model(self, request, obj, form, change):
try:
obj.save()
except Exception:
logging.exception("blah")
(或 save_new
相应)
并检查日志。
或者只使用哨兵。他们有免费套餐
我从来没有完全弄清楚到底发生了什么,但我确实设计了一个解决方法,至少可以让表单正常运行,正如我在 my answer to a related question:
中讨论的那样
Edit _get_response(self, request)
in django.core.handlers.base
. Change resolver_match = resolver.resolve(request.path_info)
to
resolver_match = resolver.resolve(request.path)
.
Add this middleware (adjust to your exact needs):
class ImageField404Middleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if (request.method == 'POST' and request.user.is_superuser and response.status_code == 302
and request.get_full_path().startswith('/pathtoadmin/')):
post_messages = get_messages(request)
for message in post_messages:
if ('was added successfully' in message.message or 'was changed successfully' in message.message
and message.level == message_levels.SUCCESS):
messages.success(request, message.message)
redirect_url = request.get_full_path()
if '_addanother' in request.POST:
redirect_url = re.sub(r'[^/]*/[^/]*/$', 'add/', redirect_url)
elif '_save' in request.POST:
redirect_url = re.sub(r'[^/]*/[^/]*/(\?.*)?$', '', redirect_url)
if '_changelist_filters' in request.GET:
preserved_filters = parse.parse_qsl(request.GET['_changelist_filters'])
redirect_url += '?' + parse.urlencode(preserved_filters)
elif '_continue' in request.POST:
redirect_url_search = re.search(r'((?<=href=)[^>]*)', message.message)
if redirect_url_search:
redirect_url = redirect_url_search.group(0)
redirect_url = re.sub(r'[\"]*', '', redirect_url).replace('/pathtoadmin/pathtoadmin/', '/pathtoadmin/')
return HttpResponseRedirect(redirect_url)
return response
Not ideal by any means, but works for me at the moment.
You can read more details here:
https://medium.com/@mnydigital/how-to-resolve-django-admin-404-post-error-966ce0dcd39d
我相信这些问题至少部分是由 ModSecurity Apache 引起的。在托管服务提供商后来重新配置后,我已经解决了一些问题。
我目前正在调试 Django 站点的一个奇怪问题,其中一个特定模型在管理界面中创建新实例或编辑现有实例时触发 404 错误。
具体是提交表单时出现的错误。我可以 GET
改变形式就好了。
这仅在实时站点上发生,并且仅在保存此模型时发生。所有其他模型都按预期运行,当我在本地 运行 时,一切都按预期运行。当以编程方式创建时,无论是在现场还是在本地,一切都很好。
这是我的模型:
class Content(models.Model):
"""Base Content class."""
title = models.CharField(max_length=200)
body = RichTextUploadingField(max_length=30000, blank=True, null=True, config_name='admin')
date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
author = models.ForeignKey(to=User, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100, null=True, default=None)
class Meta:
abstract = True
class ContentPage(Content):
"""Represents a page of generic text content."""
title = models.CharField(max_length=200, unique=True)
has_url = models.BooleanField(default=False, help_text='Sets the page to accessible via a URL.')
banner = models.ImageField(upload_to='myfiles/banners/', blank=True, null=True)
def save(self, *args, **kwargs):
"""Create the slug from the title."""
self.slug = slugify(self.title[:100])
super(ContentPage, self).save(*args, **kwargs)
ContentPage
class 是在管理界面中触发问题的原因。我从 Content
继承的另一个 class 工作正常。
我已将我的管理设置剥离为以下内容,但它仍在发生:
class CustomAdminSite(AdminSite):
def get_urls(self):
"""Define custom admin URLs."""
urls = super(CustomAdminSite, self).get_urls()
# Append some new views here...
return urls
admin_site = CustomAdminSite()
admin_site.register(ContentPage)
这是重现问题的基本 URL 配置:
from myapp.admin import admin_site
urlpatterns = [
path('mycooladminsite/', admin_site.urls),
path('', include('myapp.urls')),
]
我检查过的其他一些内容:
- 我没有干扰保存的信号。
- 我没有在模型的
save()
方法中执行任何操作。 - 我已经检查了
get_object_or_404()
个调用,但看不到任何会对此产生影响的调用。
我已经花了几个小时来研究这个问题,但我目前正处于困境。
数据库引擎为mysql.connector.django
,Django 版本为 2.2.11。我无法为该站点更改引擎或将 Django 更新为 3.x。
这是我以前没有注意到的最近的问题。
更新:
我已将问题缩小到 ImageField。当我从显示的字段中删除它时,保存时不会出现问题。
我正在使用自定义管理表单,但这似乎不是问题所在。我已经尝试使用默认值,但它仍然会发生。我一直在寻找存储 class 中的异常,但没有找到任何异常。我一路剥离它,错误仍然存在。
我在 Firefox Developer Tools 中检查了本地 302 POST
和生产 404 POST
,它们几乎相同,但生产服务器是 Apache,x-powered-by
是 Phusion Passenger,而本地服务器是 WSGIServer/0.2 CPython/3.7.3.
我实际上已经注意到 404 与现在生产中的其他 multipart/form-data
表单一起出现,这是我以前从未遇到过的。
我不知道问题是什么,但如果你没有日志,运行 它在产品上使用 DEBUG=False,不要使用 Sentry 等,只有当你保存时才会发生ContentPage
管理表单,然后您可以用
ModelAdmin
中的 save_new
或 save_model
方法
def save_model(self, request, obj, form, change):
try:
obj.save()
except Exception:
logging.exception("blah")
(或 save_new
相应)
并检查日志。
或者只使用哨兵。他们有免费套餐
我从来没有完全弄清楚到底发生了什么,但我确实设计了一个解决方法,至少可以让表单正常运行,正如我在 my answer to a related question:
中讨论的那样
Edit
_get_response(self, request)
indjango.core.handlers.base
. Changeresolver_match = resolver.resolve(request.path_info)
toresolver_match = resolver.resolve(request.path)
.Add this middleware (adjust to your exact needs):
class ImageField404Middleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) if (request.method == 'POST' and request.user.is_superuser and response.status_code == 302 and request.get_full_path().startswith('/pathtoadmin/')): post_messages = get_messages(request) for message in post_messages: if ('was added successfully' in message.message or 'was changed successfully' in message.message and message.level == message_levels.SUCCESS): messages.success(request, message.message) redirect_url = request.get_full_path() if '_addanother' in request.POST: redirect_url = re.sub(r'[^/]*/[^/]*/$', 'add/', redirect_url) elif '_save' in request.POST: redirect_url = re.sub(r'[^/]*/[^/]*/(\?.*)?$', '', redirect_url) if '_changelist_filters' in request.GET: preserved_filters = parse.parse_qsl(request.GET['_changelist_filters']) redirect_url += '?' + parse.urlencode(preserved_filters) elif '_continue' in request.POST: redirect_url_search = re.search(r'((?<=href=)[^>]*)', message.message) if redirect_url_search: redirect_url = redirect_url_search.group(0) redirect_url = re.sub(r'[\"]*', '', redirect_url).replace('/pathtoadmin/pathtoadmin/', '/pathtoadmin/') return HttpResponseRedirect(redirect_url) return response
Not ideal by any means, but works for me at the moment.
You can read more details here: https://medium.com/@mnydigital/how-to-resolve-django-admin-404-post-error-966ce0dcd39d
我相信这些问题至少部分是由 ModSecurity Apache 引起的。在托管服务提供商后来重新配置后,我已经解决了一些问题。