skip to Main Content

On production server, when I try to edit/create an object then saving fails, returning 404. This only occurs for POST requests, GET requests (loading the page) work fine.
Django is deployed via cPanel and WSGI, DEBUG is False (though it does not work even when it’s set to True)

I have deployed the Django app with cpanel, running in a virtualenv. This only seems to happen for a model that uses FileField for file upload, other models can be changed/created just fine.

The model:

def get_image_path(instance, filename):
    name, ext = filename.split('.')
    return f'images/{instance.advert_id}/{name}.{ext}'

class AdvertImage(models.Model):
    advert = models.ForeignKey(Advert, on_delete=models.CASCADE)
    image = models.ImageField(upload_to=get_image_path)

URL conf:

urlpatterns = [
                  path('i18n/', include('django.conf.urls.i18n')),
              ] + i18n_patterns(
    path('admin/', admin_site.urls),

    # ... other views....

    prefix_default_language=False
)

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Navigate to domain.com/admin/colli/advertimage/1/change/ – the page loads correctly. Fill the form, click save.

The model should be saved and no 404 should occur.
Other models, that do not use FileField, for them all admin views work correctly

With DEBUG=True, the full error message is:

Page not found (404)
Request Method: POST
Request URL:    http://example.com/admin/colli/advertimage/1/change/
Raised by:  django.contrib.admin.options.change_view
Using the URLconf defined in Colli.urls, Django tried these URL patterns, in this order:

i18n/
admin/
[name='home']
advert/<slug:slug> [name='detail']
tagauks [name='admin_list']
tagauks/lisa [name='insert']
tagauks/muuda/<int:pk> [name='edit']
tagauks/kasutaja/<int:pk> [name='user_edit']
tagauks/save_image [name='save_image']
accounts/login/ [name='login']
accounts/logout/ [name='logout']
api/
^media/(?P<path>.*)$
The current path, colli/advertimage/1/change/, didn't match any of these.

You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.

The view causing this seems to be change_view

2

Answers


  1. Have you activated middleware (Internationalization: in URL patterns)?

    # settings.py
    MIDDLEWARE = [
    ...
    'django.middleware.locale.LocaleMiddleware'
    ...
    ]
    
    Login or Signup to reply.
  2. I never got to the bottom of this, but I have developed a workaround that allows the forms to function.

    1. 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).

    2. 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.

    I believe these problems may, in part at least, be caused by ModSecurity Apache. Some problems I had went away after the hosting provider later reconfigured this.

    You can read more details here: https://medium.com/@mnydigital/how-to-resolve-django-admin-404-post-error-966ce0dcd39d

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search