For interoperability with EmberData it seems I need to reply with 422 (Unprocessable Entity) instead of 400 (Bad Request) whenever validation errors occur. I have two questions:
How can I specify the response status code when using a ModelViewSet?
Why is the 422 not listed in the list of possible return codes?
And bonus:
Why is EmberData expecting 422? This is not part of the JSONAPi spec, as far as I can see.
422 is part of the WebDAV DRF which error codes aren't in DRF.
This doesn't stop you to use it. They are just a human readable version of the number itself.
One option would be to override rest_framework.exceptions.ValidationError.status_code and set it to 422.
Edit - Changing the default error code:
# At the top of a views.py file, by the ends of import add:
from rest_framework.exceptions import ValidationError
ValidationError.status_code = 422
Related
After successful POST a redirect should happen (PRG Pattern)
response = admin_client.post(url, data)
assert response.status_code == 302
If this test fails, I get a very meaningless error message.
AssertionError assert 200 == 302
Since the status is 200, I know that the form data which I send did not validate.
Is there a django-way to get the error message of the django form validation into the exception?
Example: I would like to see something like "foo is require" (if "foo" is not in data)
Django's custom TestCase class is a subclass of unittest.TestCase and all of its assert functions have a msg argument which when passed are used as the error message when an assertion fails. Also since you want the forms error to be displayed, you can get the form instance from the context and get its errors. Something like this should work:
assertEqual(response.status_code, 302, str(response.context['form'].errors))
Note forms also have form.errors.as_data() which will show the exceptions raised during form validation, or form.errors.as_json() any of which you might find more usable. Reference Form.errors
I am trying to suppress some specific warning message of a view that's returning a 404 when the object is not found. I have tried:
try:
city = Cities.objects.get(id='abcd')
except ObjectDoesNotExist:
with warnings.catch_warnings():
return bad_request_response(_('City not found.'), resp_status=HTTP_404_NOT_FOUND)
But django seems to go around that and shows in the logs:
WARNING Not Found: /cities/abcd/
I am working with Django 1.11. I see it the docs that this is the expected behavior https://docs.djangoproject.com/en/1.11/topics/logging/#django-request but I am trying to go around that. Any hint is welcome
In setting up a ArchiveIndexView in Django I am able to successfully display a list of items in a model by navigating to the page myself.
When going to write the test in pytest to verify navigating to the page "checklist_GTD/archive/" succeeds, the test fails with the message:
> assert response.status_code == 200
E assert 301 == 200
E + where 301 = <HttpResponsePermanentRedirect status_code=301, "text/html; charset=utf-8", url="/checklist_GTD/archive/">.status_code
test_archive.py:4: AssertionError
I understand there is a way to follow the request to get the final status_code. Can someone help me with how this done in pytest-django, similar to this question? The documentation on pytest-django does not have anything on redirects. Thanks.
pytest-django provides both an unauthenticated client and a logged-in admin_client as fixtures. Really simplifies this sort of thing. Assuming for the moment that you're using admin_client because you just want to test the redirect as easily as possible, without having to log in manually:
def test_something(admin_client):
response = admin_client.get(url, follow=True)
assert response.status_code == 200
If you want to log in a standard user:
def test_something(client):
# Create user here, then:
client.login(username="foo", password="bar")
response = client.get(url, follow=True)
assert response.status_code == 200
By using follow=True in either of these, the response.status_code will equal the return code of the page after the redirect, rather than the access to the original URL. Therefore, it should resolve to 200, not 301.
I think it's not documented in pytest-django because the option is inherited from the Django test client it subclasses from (making requests).
UPDATE:
I'm getting downvoted into oblivion but I still think my answer is better so let me explain.
I still think there is a problem with Shacker's answer, where you can set follow=True and get a response code of 200 but not at the URL you expect. For example, you could get redirected unexpectedly to the login page, follow and get a response code of 200.
I understand that I asked a question on how to accomplish something with pytest and the reason I'm getting downvoted is because I provided an answer using Django's built-in TestCase class. However, the correct answer for the test is/was more important to me at the time than exclusively using pytest. As noted below, my answer still works with pytest's test discovery so I think the answer is still valid. After all, pytest is built upon Django's built-in TestCase. And my answer asserts the response code of 200 came from where I expected it to come from.
The best solution would be to modify pytest to include the expected_url as a parameter. If anyone is up for doing this I think it would be a big improvement. Thanks for reading.
ORIGINAL CONTENT:
Answering my own question here. I decided to include final expected URL using the built-in Django testing framework's assertRedirects and verify that it (1) gets redirected initially with 302 response and (2) eventually succeeds with a code 200 at the expected URL.
from django.test import TestCase, Client
def test_pytest_works():
assert 1==1
class Test(TestCase):
def test_redirect(self):
client = Client()
response = client.get("/checklist_GTD/archive/")
self.assertRedirects(response, "/expected_redirect/url", 302, 200)
Hat tip to #tdsymonds for pointing me in the right direction. I appreciated Shacker's answer but I have seen in some scenarios the redirect result being 200 when the page is redirected to an undesirable URL. With the solution above I am able to enforce the redirect URL, which pytest-django does not currently support.
Please note: This answer is compliant with the auto-discover feature of pytest-django and is thus not incompatible (it will auto-discover both pytest-django and Django TestCase tests).
I am writing some tests in Django to check the apps which I have written. I am more or less working through what is suggested on here (http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/).
However, when I put something like
resp = self.client.get('made_up_url')
self.assertEqual(resp.status_code, 404)
which doesn't exist (and hence I'm hoping for a 404 response, i.e. the test will pass)...but the test fails saying 200!=400, i.e. it seems to think that the made_up_url is a valid page.
Any ideas what could be wrong?
You are trying to self.client.get an unexistent URL: made_up_url. As dan-klasson told you, you need to get /made_up_url.
I suggest that, instead of hardcoding the URL in the self.client.get arguments, first name the related URL in your urls.py file. So you can resolve it via the reverse function.
Then, once you have a name for it, you can do this in your unit tests:
from django.core.urlresolvers import reverse
url = reverse('made_up_url')
resp = self.client.get(url)
self.assertEqual(resp.status_code, 404)
I have a website powered by django. There are few url patterns which i donot catch
say www.mysite.com/12233445 www.mysite.com/###$$$ www.mysite.com/alphabetagamma this leads to 500 error page, i want all such non-standard urls to redirect to 404 error page. Any clue which is the best method of doing it?
By using custom handler500ΒΆ you can change the response status code from 500 to 404. make your project to return this post may help you get the idea how to do it - http://ilian.i-n-i.org/custom-404-not-found-page-with-django-cms/
But as #Daniel said it isn't normal to get 500 for not found pages. Turn on the debug mode and check what error leads to 500.
Have you created a 404.html template? This happens when you have DEBUG = False in your settings.py, yet you haven't created a 404.html template. This raises a TemplateDoesNotExist exception, hence the error 500 response.
go to your views, perform all the get/filter operations within a try except block.
try:
variable = object.get(some checks here)
except: object.DoesNotExist
raise Http404
return (whatever)