Oh! And as I write this, I just noticed something. I've been testing this with $ curl -v http://localhost:8000/heknowsclydecash -o /dev/null
. I just got rid of the -o, and turns out, a clue! Curl's now spitting out 'HttpResponseNotFound' object has no attribute 'data'
.
At first when I saw that, I felt relief. I thought, as gay as this journey has been, at long last I have something I can grep for or google for or something.
And after trying to dig that up for like 15 more minutes or so... I have nothing. I tried a few other things. I tried custom 404 handler, custom 500 handler (no clue if I'm configuring any of these properly), I'm done with this.
This looks like a html response for 404 is being forced into DRF stuff where it doesn't belong.
HttpResponseNotFound is not an error, it's a html response class or object. You can use it in your code to return from a view. Django returns an object of that class when it catches a 404 error.
django.views.defaults.page_not_found
django.core.handlers.exception.response_for_exception
^ these things in django generate a 404 html page. Also, look for usages of HttpResponseNotFound in the project's code. But if you're requesting a nonexistent
http://localhost:8000/heknowsclydecash with settings.DEBUG on, you're probably hitting django.views.debug.technical_404_response by way of response_for_exception when the url resolver tries all registered patterns and fails to find a matching view.
DRF responses (rest_framework.response.Response) have a .data attribute. HttpResponseNotFound is not a DRF response.
Some custom niggerfaggotry, probably a middleware, in the code tries to access .data on the response object. (It's not DRF doing it out of the box, you
can return a html response from a DRF view, nothing will break.)
Middlewares are listed in settings (settings.MIDDLEWARE).
Middlewares are a stack of classes/functions which process requests and responses: they call one another in order on the request and are exited in reverse order on the response. A django request is accepted, passes through the layers of middleware, is routed to a view (or not routed, in which case a 404 is raised), the view returns a response or raises an error (if it does, the handler catches the error and produces a response), and that response passes back out of middleware.
Exception handlers catch errors raised by views inside the layers of middleware. If an error occurs in middleware, it will not be caught by the handler.
Exception handlers are not python loggers. Whatever produces your log record doesn't look like a python logger either.
If you can use a debugger with breakpoints, put a breakpoint in response_for_exception, look through the call stack and see where the fuckery happens. If not (why not?), look through the stack of middleware (settings.MIDDLEWARE). Each line is a namespaced class/function. Find them in the code and see if they try to access `.data` on the response. Pay special attention to a class/function that's not part of django (doesn't start with `django.`), those are the most likely culprits:
Python:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"clydecash.middleware.DatabaseRequestCounterMiddleware", # <--!!!!!!!
]
{"request": "GET /heknowsclydecash", "user_agent": "curl/8.8.0", "event": "request_started", "level": "info"}
This doesn't look like python's logger but some external stuff (sentry?). plz poast your django settings.LOGGING dict if any.
Don't run django's DEBUG=True on production.
(django's DEBUG setting has nothing to do with logging.DEBUG, unless a developer made settings.LOGGING depend on django's DEBUG, you can log DEBUG severity level messages in production just fine.)