【问题标题】:Django admin 404 error when creating or editing a model instance创建或编辑模型实例时出现 Django admin 404 错误
【发布时间】:2020-07-08 14:08:41
【问题描述】:

我目前正在调试一个 Django 站点的一个奇怪问题,其中一个特定模型在创建新实例或在管理界面中编辑现有实例时触发 404 错误。

具体来说,是在提交表单时发生的错误。我可以GETchangeform 就好了。

这仅在实时站点上发生并且仅在保存此模型时发生。所有其他模型都按预期运行,当我在本地运行它时,一切都按预期工作。当以编程方式创建时,一切都很好,无论是在现场还是在本地。

这是我的模型:

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

我检查过的其他几件事:

  • 我没有干扰保存的信号。
  • 我没有在模型的 save() 方法中执行任何操作。
  • 我已经检查了get_object_or_404() 调用,但看不到任何会影响此的调用。

我已经花了几个小时来研究这个问题,而我目前正处于一堵砖墙上。

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

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

更新:

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

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

我在 Firefox 开发人员工具中检查了本地 302 POST 和生产 404 POST,它们几乎相同,但生产服务器是 Apache,x-powered-by 是 Phusion Passenger,而本地服务器是 WSGIServer/0.2 CPython/3.7.3.

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

【问题讨论】:

标签: python django mysql-connector-python


【解决方案1】:

我不知道问题是什么,但是如果您没有日志,请使用 DEBUG=False 在 prod 上运行它,不要使用 Sentry 等,并且只有在您保存 ContentPage 管理表单时才会发生这种情况,然后你可以用

覆盖你的ModelAdmin中的save_newsave_model方法

    def save_model(self, request, obj, form, change):
        try:
            obj.save()
        except Exception:
            logging.exception("blah")

(或相应的save_new

并检查日志。

或者只使用 Sentry。他们有免费套餐

【讨论】:

  • 我刚试过这个,但save_model没有出现异常。我确实在我的handler404 视图中记录了异常,它说找不到匹配的路径......但我不知道为什么。它可以在GET 请求上正常加载页面,并且路径当然是相同的。
  • 你说它发生在表单保存时。然后尝试覆盖save_new
  • 明天试试。该问题可能在保存对象之前发生 - 看起来 ImageField/storage 类可能在抱怨某些事情,但在这个阶段不确定。将进一步研究。
  • 我应该在哪里覆盖save_new?我只知道这是一个ModelFormSet 函数。此外,在编辑现有实例时会出现问题,而不仅仅是在创建新实例时。我已将问题缩小到 ImageField 并在问题中添加了更多信息。
  • 是的,那么我认为它不适用于您的情况。 AFAIK 它就在那里。那么可能在模型上使用save 方法?
【解决方案2】:

我从未完全了解到底发生了什么,但我确实设计了一种解决方法,至少可以让表单正常运行,正如我在 my answer to a related question 中讨论的那样:

  1. django.core.handlers.base 中编辑_get_response(self, request)。将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 引起的。在托管服务提供商后来重新配置后,我已经解决了一些问题。

【讨论】:

  • 您可以使用monkey patching 来安装此修复程序,以便将来安全升级。
猜你喜欢
  • 2018-12-04
  • 2016-10-24
  • 1970-01-01
  • 1970-01-01
  • 2016-12-16
  • 1970-01-01
  • 1970-01-01
  • 2016-08-07
  • 2018-04-12
相关资源
最近更新 更多