I'm trying to set up test for some URLS that are set only in debug. They are not set because apparently the value of DEBUG change to False between my setting file and urls.py. I've never encountered this problem before, and I don't remember doing anything particularly fancy involving DEBUG value.
Here's my urls.py :
from django.conf import settings
from my_views import dnfp
print "settings.DEBUG in url: {}".format(settings.DEBUG)
if settings.DEBUG:
urlpatterns += [url(r'^dnfp/$', dnfp, name="debug_not_found_page"...
Here's my setting file :
DEBUG=True
print "DEBUG at the end of the settings: {}".format(DEBUG)
The content that fail in my test :
reverse("debug_not_found_page"),
Here's the output of the test :
DEBUG at the end of the settings: True
settings.DEBUG in url: False
Creating test database for alias 'default'...
.E
(...)
NoReverseMatch: Reverse for 'debug_not_found_page' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
If I change the value myself in urls.py the url is set again and the test works with this urls.py :
from django.conf import settings
from my_views import dnfp
settings.DEBUG = True
if settings.DEBUG:
urlpatterns += [url(r'^dnfp/$', dnfp, name="debug_not_found_page"...
Any ideas when and why my value for DEBUG is changing between settings and urls ?
From the docs
Regardless of the value of the DEBUG setting in your configuration file, all Django tests run with DEBUG=False. This is to ensure that the observed output of your code matches what will be seen in a production setting.
The problem with your code is you are setting DEBUG = True after this line
urlpatterns += [url(r'^dnfp/$', dnfp, name="debug_not_found_page"
The reason is that all the URLs are already appended to urlpatterns[] and you are setting it after the appending of URLs and while appending the URL Django actually transfer control to urls.py for syntax validation purpose. That's why you are getting different value in urls.py.
Set value of DEBUG before this line
Try this, hope it will work.
You can use another approach for doing this, create a separate app for all these type of URLs and don't add the app to INSTALLED_APPS on the basis of debug variable.
Related
In a django 1.8 project, I am attempting to redirect http://myProject/ads.txt to an external url http://a.location.that.has.the.ads.txt.file and thus serve the ads.txt file without using ftp to simply place the ads.txt in the root.
Given this minimal directory structure:
django projects
myProject
myapp
urls.py
views.py
someotherapp
yetanotherapp
myProject
settings.py
urls.py (this is the top urls.py)
views.py
in myProject/myProject/urls.py, (the “top” urls.py) I have as the first entry in the urlpatterns list, the lines:
urlpatterns = patterns('',
(r'^ads\.txt', RedirectView.as_view(url='http://a.location.that.has.the.ads.txt.file', permanent=False)),
followed by many more pattern matching regex’s. This does not work and fails with a 404. What does work is
urlpatterns = patterns('',
(r'^foo/ads\.txt', RedirectView.as_view(url='http://a.location.that.has.the.ads.txt.file', permanent=False)),
and then calling http://myProject/foo/ads.txt
Unfortunately, ads.txt files must be placed at the site root. I have tried many different regex’s that test fine in a regex validator, but just don’t work (returns 404). How do I do this without the extra dir “foo”? Any thoughts appreciated. Thank you.
Turns out you cannot redirect with the top level urls.py "routing table" to above the Django project root. A nginx server level redirect did the trick.
I have an endpoint /docs in django that I only want to be visible when DEBUG = True in settings - otherwise, it should throw a 404. My setup looks like this
urls.py
urlpatterns = ...
if settings.DEBUG:
urlpatterns += [
url(r'^docs/$', SwaggerSchemaView.as_view(), name='api_docs'),
]
When doing testing, though, django doesn't automatically reload urls.py, which means simply overriding DEBUG to True or False doesn't work.
My tests look something like this
#override_settings(DEBUG=True)
#override_settings(ROOT_URLCONF='config.urls')
class APIDocsTestWithDebug(APITestCase):
# check for 200s
...
#override_settings(DEBUG=False)
#override_settings(ROOT_URLCONF='config.urls')
class APIDocsTestWithoutDebug(APITestCase):
# check for 404s
...
Now here's the weird part: When I run the tests individually using pytest path/to/test.py::APIDocsTestWithDebug and pytest path/to/test.py::APIDocsTestWithoutDebug, both tests pass. However, if I run the test file as a whole (pytest path/to/test.py), APIDocsTestWithDebug always fails. The fact that they work individually but not together tells me that the url override is working, but when the tests are in tandem, there is some bug that messes things up. I was wondering if anybody had come across a similar issue and either has an entirely different solution or can give me some tips as to what I'm doing wrong.
I struggled with the same issue. The thing is that Django loads your urlpatterns once while initializing - and overriding the settings with the decorator doesn't change what was initially loaded.
Here's what worked for me - try reloading your urls module (based on this) and clearing url caches with clear_url_caches() before the failing test cases:
import sys
from importlib import reload, import_module
from django.conf import settings
from django.core.urlresolvers import clear_url_caches # Or -> from django.urls import clear_url_caches
def reload_urlconf(urlconf=None):
clear_url_caches()
if urlconf is None:
urlconf = settings.ROOT_URLCONF
if urlconf in sys.modules:
reload(sys.modules[urlconf])
else:
import_module(urlconf)
PS: You might also want to restore the urlpatterns later - just run reload_urlconf within other settings.
You can use #pytest.mark.urls: https://pytest-django.readthedocs.io/en/latest/helpers.html#pytest.mark.urls
#pytest.mark.urls('myapp.test_urls')
def test_something(client):
assert 'Success!' in client.get('/some_url_defined_in_test_urls/').content
You could even define the URLs within the same file:
def some_view(request):
return HttpResponse(b"Success!")
urlpatterns = [
path("some-url/", some_view)
]
#pytest.mark.urls(__name__)
def test_something(client):
assert b'Success!' in client.get('/some-url/').content
I have installed the django-contact-form module and modified my urls.py file at the root level of my django app to contain:
from django.conf.urls import include, url
urlpatterns = [
# ... other URL patterns for your site ...
url(r'^contact/', include('contact_form.urls')),
]
as per the instructions listed here:
https://django-contact-form.readthedocs.io/en/1.2/quickstart.html
But when I try and run my Django app, I get the following error:
RuntimeError: Model class django.contrib.sites.models.Site doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
I haven't added 'contact_form' to the INSTALLED_APPS setting as the guide explains that is not necessary.
Does anyone know what might be happening? Without that line in my urls.py file, the app runs fine.
Have you tried adding django.contrib.sites to the INSTALLED_APPS list in your settings.py?
When I try to use my own view for error 404, I instead get a standard error page. So, what I've done by now:
# root settings.py
DEBUG = False
ALLOWED_HOSTS = [
'*'
]
# blog urls.py
handler404 = 'views.custom_404'
# blog views.py
def custom_404(request):
return HttpResponse("Hello world, I'm a custom error 404")
And, besides, to try it locally on Django test server, I run it like this:
python manage.py runserver --insecure
But what I get when I go to some page which does not exist is:
Not Found
The requested url blablabla
So, for some reason I do not see my own message Hello world, I'm a custom error 404.
404 handlers are not per app, they can only be set from the main urls.py.
I have tried using https://docs.djangoproject.com/en/dev/topics/http/views/ tutorial, but still I am getting the standard 404 html page. I want to switch in to my custom view
handler404 = 'myview.views.custom_page_not_found' ,
I did debug it (using eclipse), then the value of handler404(old value -'django.config.default.views.page_not_found) is changed to the new value I have given ('myview.views.custom_page_not_found'). But it's still showing the older 404 page. And I have changed settings.py DEBUG into False then it shows the custom page. But it got some disadvantages (it won't load static files and all, DEBUG = false is not the right way) so I had to reset to True.
Do I have to make some other modification for implementing this?
I think you can not change the 404 page in DEBUG = True mode without difficulty.
There is a hint in the documentation (https://docs.djangoproject.com/en/dev/topics/http/views/#the-404-page-not-found-view):
If DEBUG is set to True (in your settings module), then your 404 view will never be used, and your URLconf will be displayed instead, with some debug information.
Try adding this to the bottom of your main urls.py:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^404/$', TemplateResponse, {'template': '404.html'}))
Swap out the 404.html to the appropriate template you use, I believe 404.html is the default though. Then with debug=True you can test out your 404 page.
If you want to Test it out with Debug=True then you need this at the bottom of your main urls.py instead:
#Enable static for runserver with debug false
from django.conf import settings
if settings.DEBUG is False: #if DEBUG is True it will be served automatically
urlpatterns += patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
)
When running with DEBUG = False, don't forget to collect static:
python manage.py collectstatic
Hope this helps, Cheers!