首页 > 解决方案 > 创建或编辑模型实例时出现 Django admin 404 错误

问题描述

我目前正在调试 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该类是在管理界面中触发问题的类。我的另一个继承自的类Content工作正常。

我已将我的管理员设置剥离为以下内容,但它仍在发生:

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')),
]

我检查过的其他几件事:

我花了几个小时来挖掘这个,我现在在一堵砖墙上。

数据库引擎是mysql.connector.djangoDjango 版本 2.2.11。我还不能为此站点更改引擎或将 Django 更新到 3.x。

这是我之前没有注意到的最近的一个问题。

更新:

我已将问题范围缩小到 ImageField。当我从显示的字段中删除它时,保存时不会出现问题。

我正在使用自定义管理表单,但这似乎不是问题。我试过使用默认值,它仍然会发生。我一直在寻找存储类中的异常,但没有发现任何异常。我一直把它剥离回来,错误仍然存​​在。

我在 Firefox 开发者工具中检查了本地 302POST和生产 404 POST,它们实际上是相同的,但是生产服务器是 Apache 并且x-powered-by是 Phusion Passenger,而本地服务器是 WSGIServer/0.2 CPython/3.7.3。

我实际上已经注意到multipart/form-data现在生产中的其他形式出现了 404,这是我以前从未遇到过的。

标签: pythondjangomysql-connector-python

解决方案


我从来没有完全了解发生了什么,但我确实设计了一种解决方法,至少可以让表单正常运行,正如我在对相关问题的回答中所讨论的那样:

  1. _get_response(self, request)中编辑django.core.handlers.base。更改resolver_match = resolver.resolve(request.path_info)resolver_match = resolver.resolve(request.path)

  2. 添加此中间件(根据您的确切需求进行调整):

     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
    

无论如何都不理想,但目前对我有用。

您可以在此处阅读更多详细信息: https ://medium.com/@mnydigital/how-to-resolve-django-admin-404-post-error-966ce0dcd39d

我相信这些问题至少部分是由 ModSecurity Apache 引起的。在托管服务提供商后来重新配置后,我已经解决了一些问题。


推荐阅读